Patreon API OAuth2令牌刷新疑问:能否提前刷新及400错误排查
Hey there! Let's work through your Patreon OAuth issues—first the 400 Bad Request when refreshing tokens, then how to handle token refreshes in Express without memory problems.
Why You're Getting a 400 Bad Request When Refreshing
First off: you don't need to wait for the access token to expire to refresh it—Patreon's OAuth system supports proactive token refreshes. The 400 error is almost certainly due to an implementation issue, not timing. Here are the most likely fixes:
Check the
refreshTokenmethod argument
Looking at the Patreon JS package source code, therefreshTokenmethod expects the rawrefresh_tokenstring, not the fulltokenResponseobject you're passing. Your current code:patreonOAuthClient.refreshToken(tokenResponse) // Wrong: passes the entire objectShould be updated to:
patreonOAuthClient.refreshToken(tokenResponse.refresh_token) // Correct: passes just the refresh token stringThis is the most common cause of a 400 here—passing an invalid parameter format to the method.
Verify your client credentials match
Ensure theclientIdandclientSecretused to initializepatreonOAuthClientare identical to what you used when fetching the initial access token. Mismatched credentials will throw a 400 error.Confirm refresh token scope validity
Double-check that your original token's scope (in your example,my-campaign pledges-to-me users) includes the permissions you need for future API calls. If the refresh token was issued with restricted scope, it might fail to refresh, though this usually returns a more specific error than a generic 400.
How to Handle Token Refreshes in Express Without Memory Issues
Storing tokens in server memory is risky—restarts will wipe them, and multi-server setups can't share them. Here's a robust approach:
Use persistent storage for tokens
Store access tokens, refresh tokens, and expiration timestamps in a database (like PostgreSQL) or a key-value store (like Redis). This ensures tokens survive server restarts and work across multiple Express instances.Proactive refresh before expiration
Instead of waiting for a token to fail, check its expiration timestamp before making any Patreon API call. For example, refresh the token if it's within 5 minutes of expiring:// Example function to get a valid token from storage async function getValidPatreonToken(userId) { const storedToken = await db.query('SELECT * FROM patreon_tokens WHERE user_id = $1', [userId]); const now = Date.now() / 1000; // If token is expired or about to expire, refresh it if (storedToken.expires_in <= now + 300) { // 300 seconds = 5 minutes const newTokenResponse = await patreonOAuthClient.refreshToken(storedToken.refresh_token); // Update storage with new tokens and expiration await db.query( 'UPDATE patreon_tokens SET access_token = $1, refresh_token = $2, expires_in = $3 WHERE user_id = $4', [newTokenResponse.access_token, newTokenResponse.refresh_token, now + newTokenResponse.expires_in, userId] ); return newTokenResponse.access_token; } return storedToken.access_token; }Prevent duplicate refresh requests
When multiple requests hit your server at the same time, you don't want to trigger multiple refresh calls to Patreon. Use a distributed lock (like Redis Redlock) or a database-level lock to mark a token as "refreshing" before starting the process, so other requests wait for the new token instead of initiating their own refresh.Avoid memory leaks with async operations
Make sure all database/API calls use proper error handling (try/catch blocks) to prevent unhandled promises from hanging around in memory. Also, never store tokens in request or response objects long-term—fetch them from storage when needed and discard them after use.
内容的提问来源于stack exchange,提问作者Jonathan002

