{"record":{"id":"b207bcd8e257e8ec","repo":"instructure/canvas-lms","slug":"authorization-code-not-supplied","errorCode":"authorization_code_not_supplied","errorMessage":"authorization_code_not_supplied","messagePattern":"authorization_code_not_supplied","errorType":"error_code","errorClass":"Canvas::OAuth::RequestError","httpStatus":null,"severity":"error","filePath":"lib/canvas/oauth/grant_types/authorization_code.rb","lineNumber":13,"sourceCode":"# frozen_string_literal: true\n\nmodule Canvas::OAuth\n  module GrantTypes\n    class AuthorizationCode < BaseType\n      def supported_type?\n        true\n      end\n\n      private\n\n      def validate_type\n        raise Canvas::OAuth::RequestError, :authorization_code_not_supplied unless @opts[:code]\n\n        @_token = @provider.token_for(@opts[:code])\n        raise Canvas::OAuth::RequestError, :invalid_authorization_code unless @_token.is_for_valid_code?\n        raise Canvas::OAuth::RequestError, :incorrect_client unless [@_token.key.global_id, @_token.key.id].include? @_token.client_id.to_i\n      end\n\n      def generate_token\n        @_token.create_access_token_if_needed(replace_tokens: Canvas::Plugin.value_to_boolean(@opts[:replace_tokens]))\n        Canvas::OAuth::Token.expire_code(@opts[:code])\n        @_token\n      end\n    end\n  end\nend\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/canvas/oauth/grant_types/authorization_code.rb#L1-L28","documentation":"Canvas::OAuth::GrantTypes::AuthorizationCode#validate_type raises Canvas::OAuth::RequestError with code :authorization_code_not_supplied when the token request opts lack :code. The OAuth authorization-code grant fundamentally requires the code parameter returned from the authorize step.","triggerScenarios":"POSTing to /login/oauth2/token with grant_type=authorization_code but omitting the code parameter.","commonSituations":"Client apps exchanging a code twice (code consumed, treated as absent on retry), forgetting to pass the code through a redirect handler, misbuilt token request body, dev tools dropping query params.","solutions":["Include the code parameter from the authorize redirect in the token request","Handle Canvas::OAuth::RequestError with error code authorization_code_not_supplied and surface a 400 with that code to the client","Do not reuse/retry token exchange with a consumed code; store the code before exchange and only exchange once","Check the request body encoding (form vs query) so code isn't dropped by your HTTP client"],"exampleFix":"// before\ncurl -d grant_type=authorization_code -d client_id=... -d client_secret=... /login/oauth2/token\n// after\ncurl -d grant_type=authorization_code -d client_id=... -d client_secret=... -d code=<authorization_code> -d redirect_uri=... /login/oauth2/token","handlingStrategy":"validation","validationCode":"raise 'code missing' if params[:code].blank? && params[:grant_type] == 'authorization_code'","typeGuard":"const hasCode = typeof params.code === 'string' && params.code.length > 0","tryCatchPattern":"begin\n  token = client.exchange_code_for_token\nrescue Canvas::OAuth::RequestError => e\n  render json: { error: e.error_code || 'authorization_code_not_supplied' }, status: :bad_request\nend","preventionTips":["Always carry the authorize-step code through redirects before exchanging","Exchange each authorization code exactly once","Include redirect_uri in the token request to match the authorize step"],"tags":["oauth","api","canvas"],"backgroundTag":"missing-required-argument","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"}