{"record":{"id":"ddfb0537f39df2d1","repo":"instructure/canvas-lms","slug":"invalid-client-id","errorCode":"invalid_client_id","errorMessage":"invalid_client_id","messagePattern":"invalid_client_id","errorType":"error_code","errorClass":"Canvas::OAuth::RequestError","httpStatus":400,"severity":"error","filePath":"app/controllers/oauth2_provider_controller.rb","lineNumber":52,"sourceCode":"      # browser should be closed automatically. but we'll at least display\n      # something basic.\n      return render\n    end\n\n    scopes = (params[:scope] || params[:scopes] || \"\").split\n\n    provider = Canvas::OAuth::Provider.new(\n      params[:client_id],\n      params[:redirect_uri],\n      scopes,\n      params[:purpose],\n      pkce: {\n        code_challenge: params[:code_challenge],\n        code_challenge_method: params[:code_challenge_method]\n      }\n    )\n\n    raise Canvas::OAuth::RequestError, :invalid_client_id unless provider.has_valid_key?\n    raise Canvas::OAuth::RequestError, :invalid_redirect unless provider.has_valid_redirect?\n\n    session[:oauth2] = provider.session_hash\n    session[:oauth2][:state] = params[:state] if params.key?(:state)\n    session[:oauth2][:nonce] = params[:nonce] if params.key?(:nonce)\n\n    if provider.key.require_scopes? && !provider.valid_scopes?\n      return redirect_to Canvas::OAuth::Provider.final_redirect(self,\n                                                                state: params[:state],\n                                                                error: \"invalid_scope\",\n                                                                error_description: \"A requested scope is invalid, unknown, malformed, or exceeds the scope granted by the resource owner. \" \\\n                                                                                   \"The following scopes were requested, but not granted: #{provider.missing_scopes.to_sentence(locale: :en)}\")\n    end\n\n    unless provider.key.authorized_for_account?(@domain_root_account)\n      return redirect_to Canvas::OAuth::Provider.final_redirect(self,\n                                                                state: params[:state],\n                                                                error: \"unauthorized_client\",","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/controllers/oauth2_provider_controller.rb#L34-L70","documentation":"Canvas raises Canvas::OAuth::RequestError with :invalid_client_id in the OAuth2 /login/oauth2/auth flow when the provided client_id does not correspond to a Developer Key with a valid api key (provider.has_valid_key? returns false). It mirrors the OAuth2 spec's invalid_client error for the authorization endpoint. It means the app initiating the login is not a registered/valid Canvas developer key.","triggerScenarios":"GET/POST /login/oauth2/auth with a client_id param that is missing, mistyped, points to a deleted developer key, or a key whose API key is blank/inactive.","commonSituations":"Using a dev key from a different Canvas environment (test vs production), a key that was deleted or deactivated by an admin, a client_id copied from docs/examples, or forgetting to create the developer key at /accounts/self/developer_keys before integrating.","solutions":["Verify the developer key exists and is active in Canvas admin (/accounts/self/developer_keys) and copy its exact client ID (the numeric key id)","Check that you are pointing at the correct Canvas base URL for that key (keys do not transfer across environments)","If the key is intentionally new, activate it (and get it allow-listed on self-hosted/managed installs) before starting the auth flow","Correct the client_id value in your OAuth config/env vars; ensure it is sent as the client_id query param on /login/oauth2/auth"],"exampleFix":"// before\nwindow.location = canvasUrl + '/login/oauth2/auth?client_id=' + process.env.CANVAS_KEY_ID_TODO\n// after\nwindow.location = canvasUrl + '/login/oauth2/auth?client_id=' + CANVAS_DEVELOPER_KEY_ID // verified active in Canvas admin","handlingStrategy":"validation","validationCode":"const isValidClientId = (id) => typeof id === 'string' && /^\\d{6,}$/.test(id) && Boolean(CANVAS_KEYS[id]);\nif (!isValidClientId(config.clientId)) throw new Error('Canvas developer key client_id missing/invalid — check Canvas admin developer keys');","typeGuard":"const isRegisteredKey = (id) => typeof id === 'string' && id in registeredDeveloperKeys;\nif (!isRegisteredKey(clientId)) failFast('invalid client_id before starting OAuth flow');","tryCatchPattern":null,"preventionTips":["Store the client_id per environment (test/prod) in env config, never hardcode","Assert the developer key is active during deploy/health checks","Document who owns each dev key so deletions are announced","Log the client_id (not the secret) on auth failures to speed triage"],"tags":["oauth2","authentication","developer-key","canvas-lms"],"backgroundTag":"missing-api-key","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}