{"record":{"id":"5f8a6a0326bff722","repo":"instructure/canvas-lms","slug":"invalid-jwt-audience-audience","errorCode":null,"errorMessage":"Invalid JWT audience: %{audience}","messagePattern":"Invalid JWT audience: %(.+?)","errorType":"validation","errorClass":"OAuthValidationError","httpStatus":null,"severity":"error","filePath":"app/models/authentication_provider/open_id_connect.rb","lineNumber":283,"sourceCode":"        retry\n      end\n      e.message\n    rescue JSON::JWT::VerificationFailed => e\n      e.message\n    end\n\n    def claims(token)\n      token.options[:claims] ||= begin\n        id_token = unverified_id_token(token)\n\n        unless (missing_claims = %w[aud iss iat exp nonce] - id_token.keys).empty?\n          raise OAuthValidationError, t({ one: \"Missing claim %{claims}\", other: \"Missing claims %{claims}\" },\n                                        count: missing_claims.length,\n                                        claims: missing_claims.join(\", \"))\n        end\n\n        unless Array(id_token[\"aud\"]).include?(client_id)\n          raise OAuthValidationError, t(\"Invalid JWT audience: %{audience}\", audience: id_token[\"aud\"].inspect)\n        end\n\n        if self.class.validate_issuer?\n          if issuer.blank?\n            raise OAuthValidationError, t(\"No issuer configured for OpenID Connect provider\")\n          end\n          unless issuer === id_token[\"iss\"] # rubocop:disable Style/CaseEquality -- may be a string or a RegEx\n            raise OAuthValidationError, t(\"Invalid JWT issuer: %{issuer}\", issuer: id_token[\"iss\"])\n          end\n        end\n        unless id_token[\"nonce\"] == token.options[:nonce]\n          raise OAuthValidationError, t(\"Invalid nonce claim in ID Token\")\n        end\n\n        if (signature_error = validate_signature(id_token))\n          raise OAuthValidationError, t(\"Invalid signature: %{signature_error}\", signature_error:)\n        end\n","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/authentication_provider/open_id_connect.rb#L265-L301","documentation":"Raised in claims() when the ID token's aud (audience) claim does not include this provider's configured client_id. Canvas requires that the ID token was issued specifically for its OAuth client; otherwise the token may belong to another app and is rejected as an audience mismatch.","triggerScenarios":"claims(token) is invoked from unique_id/persist_to_session/provider_attributes; Array(id_token['aud']).include?(client_id) is false — the aud claim holds a different client ID, or the provider's client_id was changed/rotated after the token was issued.","commonSituations":"Admin regenerated OAuth credentials and the Canvas provider still has the old client_id (or vice versa); IdP issues tokens with azp/aud pointing to another registered app; copy-paste of client_id with whitespace or from the wrong app registration; multiple Canvas OpenID Connect providers sharing one IdP app.","solutions":["Confirm the client_id configured on the Canvas OpenID Connect provider exactly matches the aud claim in the rejected token.","Re-issue credentials on the IdP and update client_id/client_secret in Canvas, then retry login.","On the IdP, ensure the token is issued to the correct application (check azp/authorized party settings).","Decode the failing ID token and compare aud against the provider settings before changing anything."],"exampleFix":"# before (Canvas provider settings)\nclient_id: \"old-client-id\"\n# after\nclient_id: \"the-client-id-matching-aud-claim\"","handlingStrategy":"validation","validationCode":"payload = JSON.parse(Base64.urlsafe_decode64(id_token.split(\".\")[1]))\naud = Array(payload[\"aud\"])\nraise \"aud mismatch: #{payload['aud'].inspect} vs #{CLIENT_ID}\" unless aud.include?(CLIENT_ID)","typeGuard":null,"tryCatchPattern":"begin\n  provider.claims(token)\nrescue OAuthValidationError => e\n  Rails.logger.error(\"OIDC audience validation failed: #{e.message}\")\n  head :unauthorized\nend","preventionTips":["Keep client_id in Canvas and the IdP app registration in sync","Regenerate both sides together when rotating credentials","Compare aud in the error against the provider settings before changing anything","Avoid whitespace when pasting client_id"],"tags":["oidc","jwt","sso","audience-mismatch"],"backgroundTag":"unexpected-response-shape","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"}