{"record":{"id":"953e36299374af13","repo":"discordjs/discord.js","slug":"a-client-secret-must-be-provided-for-authorization","errorCode":null,"errorMessage":"A client secret must be provided for authorization if scopes are included","messagePattern":"A client secret must be provided for authorization if scopes are included","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/rpc/src/client.ts","lineNumber":246,"sourceCode":"\t\tif (!clientId) {\n\t\t\tthrow new Error('A client id must be provided to login');\n\t\t}\n\n\t\tthis.clientId = clientId;\n\n\t\tawait this.connect(options);\n\n\t\tif (!this.options.scopes) {\n\t\t\tthis.emit(Events.ApplicationReady);\n\t\t\treturn this;\n\t\t}\n\n\t\tif (accessToken) {\n\t\t\treturn this.authenticate(accessToken, options);\n\t\t}\n\n\t\tif (!clientSecret) {\n\t\t\tthrow new Error('A client secret must be provided for authorization if scopes are included');\n\t\t}\n\n\t\tthis.clientSecret = clientSecret;\n\n\t\tconst authorizeArgs: RPCAuthorizeArgs = { client_id: this.clientId, scopes: this.options.scopes };\n\t\tif (this.options.username) authorizeArgs.username = this.options.username;\n\n\t\treturn this.authenticate(await this.authorize(authorizeArgs, options), options);\n\t}\n\n\t/**\n\t * Request\n\t *\n\t * @param cmd - Command\n\t * @param args - Arguments\n\t * @param evt - Event\n\t */\n\tpublic async request<Cmd extends RPCCallableCommands = RPCCallableCommands>(","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/discordjs/discord.js/blob/a81ed8a306d37fdc746e26a634b6a42164ba2c8c/packages/rpc/src/client.ts#L228-L264","documentation":"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.","triggerScenarios":"Calling client.login({ clientId, scopes: [...] }) (or with scopes in constructor options) without passing clientSecret and without an accessToken.","commonSituations":"Developers porting bot-token login code to the RPC client, forgetting DISCORD_CLIENT_SECRET in env, or copying examples that omit the secret.","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"],"exampleFix":"// before\nawait client.login({ clientId: '123' });\n// after\nawait client.login({ clientId: '123', clientSecret: process.env.DISCORD_CLIENT_SECRET });","handlingStrategy":"validation","validationCode":"if (!options.accessToken && !options.clientSecret && options.scopes?.length) {\n  throw new Error('login() with scopes requires clientSecret or accessToken');\n}","typeGuard":"function canLoginWithScopes(o: { accessToken?: string; clientSecret?: string; scopes?: string[] }): boolean {\n  return Boolean(o.accessToken) || !o.scopes?.length || Boolean(o.clientSecret);\n}","tryCatchPattern":"try {\n  await client.login(opts);\n} catch (err) {\n  if (err.message.includes('client secret')) console.error('Provide DISCORD_CLIENT_SECRET');\n  else throw err;\n}","preventionTips":["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"],"tags":["oauth","configuration","missing-argument"],"backgroundTag":"missing-credentials","analyzedSha":"a81ed8a306d37fdc746e26a634b6a42164ba2c8c","analyzedAt":"2026-08-30T04:07:22.193Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}