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

  1. Pass clientSecret to login() or set it in the RPC client options
  2. Provide an accessToken instead if you already have one, which skips the authorize flow
  3. 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

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


AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30). Data as JSON: /api/errors/953e36299374af13. Report an issue: GitHub.