{"record":{"id":"1128be4d4a2331ed","repo":"instructure/canvas-lms","slug":"assertion-method-not-supported-for-this-grant-type","errorCode":null,"errorMessage":"assertion method not supported for this grant_type","messagePattern":"assertion method not supported for this grant_type","errorType":"exception","errorClass":"Canvas::OAuth::InvalidRequestError","httpStatus":null,"severity":"error","filePath":"lib/canvas/oauth/grant_types/client_credentials.rb","lineNumber":74,"sourceCode":"          )\n        end\n\n        Canvas::OAuth::SymmetricClientCredentialsProvider.new(client_id, host, scopes: scopes_from_opts(opts), protocol:)\n      end\n\n      def secret_for(provider, opts)\n        provider.try(:secret) || opts[:client_secret]\n      end\n\n      def key_for(client_id)\n        DeveloperKey.find_cached(client_id)\n      rescue ::ActiveRecord::RecordNotFound\n        nil\n      end\n\n      def validate_type\n        unless @provider.assertion_method_permitted?\n          raise Canvas::OAuth::InvalidRequestError, \"assertion method not supported for this grant_type\"\n        end\n\n        raise Canvas::OAuth::InvalidRequestError, @provider.error_message unless @provider.valid?\n        raise Canvas::OAuth::InvalidScopeError, @provider.missing_scopes unless @provider.valid_scopes?\n      end\n\n      def generate_token\n        @provider.generate_token\n      end\n\n      def basic_auth?(opts)\n        opts[:client_assertion_type] != \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"\n      end\n\n      def scopes_from_opts(opts)\n        (opts[:scope] || opts[:scopes] || \"\").split\n      end\n    end","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/canvas/oauth/grant_types/client_credentials.rb#L56-L92","documentation":"Canvas's OAuth2 client_credentials grant rejects the request when the selected provider says the JWT 'client_assertion' (assertion) method is not permitted for this key's client_credentials audience. Each provider defines assertion_method_permitted?; e.g. SymmetricClientCredentialsProvider permits it only when the developer key's client_credentials_audience is 'external'. The token endpoint raises Canvas::OAuth::InvalidRequestError before any token is issued.","triggerScenarios":"POST to /login/oauth2/token with grant_type=client_credentials where (a) a JWT client_assertion is sent but the developer key's client_credentials_audience is not set to 'external' (falls through to SymmetricClientCredentialsProvider), (b) no client_assertion_type of urn:ietf:params:oauth:client-assertion-type:jwt-bearer is sent so a symmetric provider is chosen whose key audience disallows it, or (c) a service-user key path whose provider does not permit assertion auth.","commonSituations":"Key created without configuring client_credentials_audience; switching an integration from client_id/client_secret to JWT assertion without updating the key; copy of a key in a different account/shard missing the audience setting; typo in client_assertion_type URI so the asymmetric provider is never selected.","solutions":["Open the developer key in Canvas admin and set its client_credentials audience to 'external' (or, for service auth, use the site-admin service key).","If using JWT assertion, send client_assertion_type exactly as urn:ietf:params:oauth:client-assertion-type:jwt-bearer along with client_assertion.","Verify you are hitting the token endpoint on the correct root account/shard where the key with the right audience is cached.","If you do not intend assertion auth, authenticate with client_id + client_secret instead and ensure the key permits symmetric client credentials."],"exampleFix":"// before\ncurl -d 'grant_type=client_credentials&client_id=123&client_secret=xyz' https://canvas/login/oauth2/token\n// after (key configured with client_credentials_audience=external)\ncurl -d 'grant_type=client_credentials&client_assertion=<jwt>&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' https://canvas/login/oauth2/token","handlingStrategy":"validation","validationCode":"def client_credentials_request_valid?(key, opts)\n  assertion = opts[:client_assertion_type] == 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'\n  if assertion\n    key.client_credentials_audience == 'external'\n  else\n    key.client_credentials_audience != 'external'\n  end\nend","typeGuard":"def jwt_assertion?(opts)\n  opts.is_a?(Hash) && opts[:client_assertion_type] == 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' && opts[:client_assertion].present?\nend","tryCatchPattern":"begin\n  token = exchange_client_credentials(opts)\nrescue Canvas::OAuth::InvalidRequestError => e\n  logger.warn(\"client_credentials rejected: #{e.message}\")\n  # fix key config or fall back to symmetric flow\nend","preventionTips":["Set the developer key's client_credentials audience to 'external' before using JWT assertion","Send client_assertion_type exactly as urn:ietf:params:oauth:client-assertion-type:jwt-bearer","Decide on one auth mode (assertion vs secret) per key and configure the key accordingly","Test the token endpoint after any key audience change"],"tags":["oauth2","canvas-lms","client-credentials","jwt-assertion","misconfiguration"],"backgroundTag":"invalid-config-value","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"}