PHP环境下OAuth2访问令牌存储与Discord授权相关技术问题咨询
Hey there! Let's walk through each of your Discord OAuth integration questions with practical, secure solutions—this stuff is crucial for keeping your app safe and user-friendly.
1. When Should I Refresh the Access Token?
First off, when you exchange the authorization code for an access token, Discord also sends you a refresh_token (this is the key to avoiding repeated logins you’re worried about). Here’s the plan:
- Store the right data: Save the
access_token, itsexpires_invalue (7 days = 604800 seconds), the timestamp when you obtained it, and therefresh_tokenin your database tied to the user’s account. - Two reliable refresh strategies:
- Proactive check: Every time you need to call the Discord API, calculate if the token is about to expire (e.g., within the next 15-30 minutes). If yes, use the
refresh_tokento fetch a newaccess_token(note: Discord may invalidate the oldrefresh_tokenafter use, so be sure to update your database with the new one). - Reactive refresh: If you get a
401 Unauthorizedresponse from Discord, trigger the refresh flow then, then retry the API call. This is simpler but adds a tiny bit of overhead on that first failed request.
Either way, you won’t need to prompt users to re-login every 7 days as long as theirrefresh_tokenremains valid (it stays active until the user revokes your app’s access).
- Proactive check: Every time you need to call the Discord API, calculate if the token is about to expire (e.g., within the next 15-30 minutes). If yes, use the
2. Where Should I Store the Access Token? Client or Database?
Never store the access token on the client side—not in localStorage, not in regular cookies. Client-side storage is vulnerable to XSS attacks, which would let attackers steal the token and act on the user’s behalf.
The correct approach is to store the access token (and refresh token) in your server-side database, tied to each user’s account. The client only needs a session ID (stored in an HttpOnly, Secure cookie) that your server uses to look up the user’s token data when needed. This keeps sensitive tokens out of reach of client-side threats.
3. Should I Hash the Access Token in the Database? How to Handle This in PHP?
Wait a second—hashes are one-way functions, meaning you can’t reverse them to get the original token back. And you need the original token to call Discord’s API, so hashing won’t work here. Instead, you should encrypt the token before storing it in the database, so you can decrypt it when you need to use it.
Here’s a secure implementation using PHP’s OpenSSL extension (AES-256-GCM is a strong, authenticated encryption algorithm):
First, generate a 32-byte encryption key (run this once, save the output somewhere safe—don’t hardcode it!):
// Generate a secure key (run this once, store the result securely) echo base64_encode(random_bytes(32));
Then use these encrypt/decrypt functions:
function encryptDiscordToken(string $token, string $key): string { $key = base64_decode($key); $iv = random_bytes(openssl_cipher_iv_length('aes-256-gcm')); $tag = ''; $encryptedToken = openssl_encrypt( $token, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag ); // Combine IV, tag, and encrypted token for storage return base64_encode($iv . $tag . $encryptedToken); } function decryptDiscordToken(string $encryptedToken, string $key): string { $key = base64_decode($key); $data = base64_decode($encryptedToken); $ivLength = openssl_cipher_iv_length('aes-256-gcm'); $iv = substr($data, 0, $ivLength); $tag = substr($data, $ivLength, 16); // GCM tags are 16 bytes $encrypted = substr($data, $ivLength + 16); return openssl_decrypt( $encrypted, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag ); }
When storing the token, pass it through encryptDiscordToken first. When you need to call Discord’s API, decrypt it with decryptDiscordToken.
4. Where to Store CLIENT_ID and CLIENT_SECRET? Is Hardcoding in PHP Files Safe?
Hardcoding these values in your PHP files is a big no-no. If your code gets leaked (e.g., accidentally pushed to GitHub, or your server is compromised), attackers can steal these credentials and impersonate your app.
Instead, store them in environment variables:
- Use a
.envfile (with thevlucas/phpdotenvComposer package to load it) to define your secrets:DISCORD_CLIENT_ID=your-client-id-here DISCORD_CLIENT_SECRET=your-client-secret-here - Add
.envto your.gitignoreso it never gets committed to version control. - In your PHP code, retrieve them with
getenv():$clientId = getenv('DISCORD_CLIENT_ID'); $clientSecret = getenv('DISCORD_CLIENT_SECRET');
If you’re using a server like Apache or Nginx, you can also set environment variables directly in your server config instead of using a .env file—either way, keep these values out of your codebase.
内容的提问来源于stack exchange,提问作者Elyas Behroozizade




