instructure/canvas-lms · error · OAuthValidationError

No issuer configured for OpenID Connect provider

Error message

No issuer configured for OpenID Connect provider

What it means

Raised in claims() when issuer validation is enabled (self.class.validate_issuer?) but the provider has no issuer configured (issuer is blank). Canvas refuses to validate an ID token against an unknown issuer, so it fails closed instead of trusting the token.

Solutions

  1. Set the issuer on the provider (e.g. https://idp.example.com or the realm's issuer URL from the IdP's discovery document /.well-known/openid-configuration).
  2. If issuer validation is not wanted, disable validate_issuer for the provider.
  3. Verify the issuer string matches exactly what the IdP puts in the iss claim (scheme, host, path, trailing slash).

Example fix

# before
provider.settings = { "client_id" => "abc" }
# after
provider.settings = { "client_id" => "abc", "issuer" => "https://idp.example.com/realms/main" }
Defensive patterns

Strategy: validation

Validate before calling

raise "issuer missing on OIDC provider" if provider.settings["issuer"].blank?
# fetch authoritative value:
issuer = JSON.parse(Net::HTTP.get(URI("#{base_url}/.well-known/openid-configuration")))["issuer"]

Try / catch

begin
  provider.claims(token)
rescue OAuthValidationError => e
  Rails.logger.error("OIDC issuer not configured: #{e.message}")
  flash[:error] = "OpenID Connect provider misconfigured; contact an admin."
end

Prevention

When it happens

Trigger: An OpenID Connect authentication provider with validate_issuer enabled is saved/used without an issuer value in its settings; the first login calls claims() via unique_id/provider_attributes and hits the blank-issuer check.

Common situations: Admin enabled strict issuer validation but left the issuer field empty; issuer was never set because the provider was created via API/import with partial settings; upgrade turned on issuer validation by default for existing providers missing the setting.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/5deafe6b3da714fb. Report an issue: GitHub.

Appendix: source

Thrown at app/models/authentication_provider/open_id_connect.rb:288

    end

    def claims(token)
      token.options[:claims] ||= begin
        id_token = unverified_id_token(token)

        unless (missing_claims = %w[aud iss iat exp nonce] - id_token.keys).empty?
          raise OAuthValidationError, t({ one: "Missing claim %{claims}", other: "Missing claims %{claims}" },
                                        count: missing_claims.length,
                                        claims: missing_claims.join(", "))
        end

        unless Array(id_token["aud"]).include?(client_id)
          raise OAuthValidationError, t("Invalid JWT audience: %{audience}", audience: id_token["aud"].inspect)
        end

        if self.class.validate_issuer?
          if issuer.blank?
            raise OAuthValidationError, t("No issuer configured for OpenID Connect provider")
          end
          unless issuer === id_token["iss"] # rubocop:disable Style/CaseEquality -- may be a string or a RegEx
            raise OAuthValidationError, t("Invalid JWT issuer: %{issuer}", issuer: id_token["iss"])
          end
        end
        unless id_token["nonce"] == token.options[:nonce]
          raise OAuthValidationError, t("Invalid nonce claim in ID Token")
        end

        if (signature_error = validate_signature(id_token))
          raise OAuthValidationError, t("Invalid signature: %{signature_error}", signature_error:)
        end

        # we have a userinfo endpoint, and we don't have everything we want,
        # then request more
        if userinfo_endpoint.present? && !(requested_claims - id_token.keys).empty?
          userinfo = token.get(userinfo_endpoint).parsed
          debug_set(:userinfo, userinfo.to_json) if instance_debugging

View on GitHub (pinned to 1c9f0bb801)