discordjs/discord.js · error · Error
A client secret must be provided for authorization if scopes
Error message
A client secret must be provided for authorization if scopes are included
What it means
Thrown by the RPC client's login() when the caller requests OAuth scopes but provides no clientSecret. Scopes require the OAuth2 authorization-code flow, which cannot complete without the app's client secret to exchange the code for a token.
Source
Thrown at packages/rpc/src/client.ts:246
if (!clientId) {
throw new Error('A client id must be provided to login');
}
this.clientId = clientId;
await this.connect(options);
if (!this.options.scopes) {
this.emit(Events.ApplicationReady);
return this;
}
if (accessToken) {
return this.authenticate(accessToken, options);
}
if (!clientSecret) {
throw new Error('A client secret must be provided for authorization if scopes are included');
}
this.clientSecret = clientSecret;
const authorizeArgs: RPCAuthorizeArgs = { client_id: this.clientId, scopes: this.options.scopes };
if (this.options.username) authorizeArgs.username = this.options.username;
return this.authenticate(await this.authorize(authorizeArgs, options), options);
}
/**
* Request
*
* @param cmd - Command
* @param args - Arguments
* @param evt - Event
*/
public async request<Cmd extends RPCCallableCommands = RPCCallableCommands>(View on GitHub (pinned to a81ed8a306)
Solutions
- Pass clientSecret to login() or set it in the RPC client options
- Provide an accessToken instead if you already have one, which skips the authorize flow
- Remove the scopes option if you only need the local RPC connection without OAuth
Example fix
// before
await client.login({ clientId: '123' });
// after
await client.login({ clientId: '123', clientSecret: process.env.DISCORD_CLIENT_SECRET }); Defensive patterns
Strategy: validation
Validate before calling
if (!options.accessToken && !options.clientSecret && options.scopes?.length) {
throw new Error('login() with scopes requires clientSecret or accessToken');
} Type guard
function canLoginWithScopes(o: { accessToken?: string; clientSecret?: string; scopes?: string[] }): boolean {
return Boolean(o.accessToken) || !o.scopes?.length || Boolean(o.clientSecret);
} Try / catch
try {
await client.login(opts);
} catch (err) {
if (err.message.includes('client secret')) console.error('Provide DISCORD_CLIENT_SECRET');
else throw err;
} Prevention
- Load clientSecret from env and assert it at startup
- Prefer accessToken when you already completed OAuth out-of-band
- Only pass scopes when you actually need OAuth authorization
When it happens
Trigger: Calling client.login({ clientId, scopes: [...] }) (or with scopes in constructor options) without passing clientSecret and without an accessToken.
Common situations: Developers porting bot-token login code to the RPC client, forgetting DISCORD_CLIENT_SECRET in env, or copying examples that omit the secret.
Related errors
- A client id must be provided to login
- Package ${packageName} not releaseable
- The --tag option can only be used with --dev
- ClientMissingIntents
- Cannot set an interval greater than 4 hours
AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30).
Data as JSON: /api/errors/953e36299374af13.
Report an issue: GitHub.