Discord OAuth2返回{"error": "access_denied"}问题求助
Hey there, let's break down why you're hitting that {"error": "access_denied"} response from Discord's OAuth2 API—this is a super common gotcha when setting up Discord integrations, so let's walk through the most likely fixes step by step.
First things first, Discord’s OAuth2 system is strict about matching configurations:
- Redirect URI Exact Match: Make sure the redirect URI you’ve set in your Express code and the one listed in your Discord app’s "OAuth2 > Redirects" tab are identical. That includes
httpvshttps(critical since you’re using Nginx reverse proxy—if you’ve enabled SSL, it must behttps), the full path, and even trailing slashes. A tiny mismatch here will triggeraccess_deniedinstantly. - Required Scopes: Since you’re trying to auto-invite users to a guild, you need the
guilds.joinscope, plus at least one identity scope likeidentifyso Discord can verify the user. If you’re missingguilds.joinor requesting scopes the user didn’t approve, Discord will reject the request. - Valid Credentials: Confirm your Client ID, Client Secret, and Bot Token (if you’re using a bot to handle guild invites) are copied correctly from the developer portal. Typos here are way easier to make than you think!
When you redirect users to Discord’s authorization page, make sure all parameters are correct:
- The
response_typemust becode(you’re using the authorization code flow, right? That’s the standard for server-side apps). - Avoid using
prompt=noneunless you’re certain the user has already authorized your app. If you forceprompt=noneon a first-time user, Discord will immediately returnaccess_deniedinstead of showing the authorization screen. - After the user approves (or denies), check the callback request’s query params: if
req.query.errorisaccess_denied, that means the user clicked "Cancel" instead of "Authorize"—you’ll need to handle that case with a prompt to re-authorize.
Since you’re using the request library to hit Discord’s /oauth2/token endpoint, there are a few easy mistakes that cause this error:
- Content-Type Matters: Discord only accepts
application/x-www-form-urlencodedfor this endpoint—not JSON. If you’re sending a JSON body, that’s definitely the issue. - Required Parameters: Your POST body must include all of these:
client_idclient_secretgrant_type(set toauthorization_code—no exceptions)code(the authorization code from the callback)redirect_uri(again, exact match to your portal setting)
- Here’s a quick example of what the correct
requestcall should look like (with sensitive info redacted):
request.post({ url: 'https://discord.com/api/oauth2/token', form: { // Use `form` instead of `json` to get the right Content-Type client_id: 'YOUR_CLIENT_ID', client_secret: 'YOUR_CLIENT_SECRET', grant_type: 'authorization_code', code: req.query.code, redirect_uri: 'https://your-domain.com/discord/callback' } }, (err, res, body) => { // Handle the token response here });
Since you’re using Nginx to proxy your Express server, make sure it’s not messing with your requests:
- Enable trust proxy in Express: Add
app.set('trust proxy', true)to your code. This ensures Express picks up the correcthttpsprotocol (instead ofhttp) from Nginx, which keeps your redirect URI consistent. - Verify parameter passing: Log
req.query.codein your callback route to make sure the authorization code is being passed correctly through Nginx. If it’s missing or corrupted, that’ll break the token exchange.
One last thing: If you’re using a bot to handle the guild invite, make sure the bot is actually in your target guild and has the Create Instant Invite permission. Without that, even if your OAuth2 flow works, the bot won’t be able to add the user to the guild (though this usually throws a different error, but it’s worth checking!).
If you’ve gone through all these steps and still see the error, feel free to share redacted snippets of your authorization URL and token exchange code—we can dig deeper from there.
内容的提问来源于stack exchange,提问作者Nathan Hall

