Files
upstream-ory-kratos/selfservice/strategy/oidc/provider_config.go
upstream-mirror c60cc7ca75
Some checks failed
CI / Run tests and lints (push) Failing after 29s
CI / Build CLI docs (push) Has been skipped
CI / Run Playwright end-to-end tests (mysql) (push) Failing after 3s
CI / Run Playwright end-to-end tests (postgres) (push) Failing after 2s
CI / Run Playwright end-to-end tests (sqlite) (push) Failing after 3s
CodeQL / Analyze (go) (push) Failing after 4s
CodeQL / Analyze (javascript) (push) Failing after 3s
Docker Image Scanners / scanners (push) Failing after 4s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Run end-to-end tests (postgres) (push) Failing after 19s
CI / Run end-to-end tests (sqlite) (push) Failing after 2s
CI / Run Playwright end-to-end tests (cockroach) (push) Failing after 2s
CI / Draft newsletter (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/kratos.git (master, 2026-09-15; blobs > 131072B omitted)
2026-09-15 21:19:12 +05:00

281 lines
12 KiB
Go

// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package oidc
import (
"encoding/json"
"maps"
"net/url"
"slices"
"strings"
"github.com/pkg/errors"
"github.com/ory/herodot"
"github.com/ory/kratos/identity"
"github.com/ory/x/urlx"
)
const (
// AccountLinkingModeVerifyWithExistingCredential requires the user to verify their identity
// with an existing credential before accounts are linked.
AccountLinkingModeVerifyWithExistingCredential = "confirm_with_existing_credential"
// AccountLinkingModeAutomatic silently links accounts if the provider verifies email ownership.
AccountLinkingModeAutomatic = "automatic"
// ProviderTypeApple is the provider type for Sign in with Apple.
ProviderTypeApple = "apple"
// ProviderTypeGoogle is the provider type for Sign in with Google.
ProviderTypeGoogle = "google"
// UpdateIdentityOnLoginNever disables identity updates on login (default).
UpdateIdentityOnLoginNever = "never"
// UpdateIdentityOnLoginAutomatic re-runs the Jsonnet claims mapper on every
// OIDC login and updates the identity's traits and metadata automatically.
UpdateIdentityOnLoginAutomatic = "automatic"
)
type Configuration struct {
// ID is the provider's ID
ID string `json:"id"`
// Provider is either "generic" for a generic OAuth 2.0 / OpenID Connect Provider or one of:
// - generic
// - google
// - github
// - github-app
// - gitlab
// - microsoft
// - discord
// - salesforce
// - slack
// - facebook
// - auth0
// - vk
// - yandex
// - apple
// - spotify
// - netid
// - dingtalk
// - linkedin
// - patreon
// - amazon
// - uaepass
Provider string `json:"provider"`
// Label represents an optional label which can be used in the UI generation.
Label string `json:"label"`
// ClientID is the application's Client ID.
ClientID string `json:"client_id"`
// ClientSecret is the application's secret.
ClientSecret string `json:"client_secret"`
// IssuerURL is the OpenID Connect Server URL. You can leave this empty if `provider` is not set to `generic`.
// If set, neither `auth_url` nor `token_url` are required.
IssuerURL string `json:"issuer_url"`
// AuthURL is the authorize url, typically something like: https://example.org/oauth2/auth
// Should only be used when the OAuth2 / OpenID Connect server is not supporting OpenID Connect Discovery and when
// `provider` is set to `generic`.
AuthURL string `json:"auth_url"`
// TokenURL is the token url, typically something like: https://example.org/oauth2/token
// Should only be used when the OAuth2 / OpenID Connect server is not supporting OpenID Connect Discovery and when
// `provider` is set to `generic`.
TokenURL string `json:"token_url"`
// Tenant is the Azure AD Tenant to use for authentication, and must be set when `provider` is set to `microsoft`.
// Can be either `common`, `organizations`, `consumers` for a multitenant application or a specific tenant like
// `8eaef023-2b34-4da1-9baa-8bc8c9d6a490` or `contoso.onmicrosoft.com`.
Tenant string `json:"microsoft_tenant"`
// SubjectSource is a flag which controls from which endpoint the subject identifier is taken by microsoft provider.
// Can be either `userinfo` or `me` or `oid`.
// If the value is `userinfo` then the subject identifier is taken from sub field of userinfo standard endpoint response.
// If the value is `me` then the `id` field of https://graph.microsoft.com/v1.0/me response is taken as subject.
// If the value is `oid` then the the oid (Object ID) is taken to identify users across different services.
// The default is `userinfo`.
SubjectSource string `json:"subject_source"`
// TeamId is the Apple Developer Team ID that's needed for the `apple` `provider` to work.
// It can be found Apple Developer website and combined with `apple_private_key` and `apple_private_key_id`
// is used to generate `client_secret`
TeamId string `json:"apple_team_id"`
// PrivateKeyId is the private Apple key identifier. Keys can be generated via developer.apple.com.
// This key should be generated with the `Sign In with Apple` option checked.
// This is needed when `provider` is set to `apple`
PrivateKeyId string `json:"apple_private_key_id"`
// PrivateKeyId is the Apple private key identifier that can be downloaded during key generation.
// This is needed when `provider` is set to `apple`
PrivateKey string `json:"apple_private_key"`
// Scope specifies optional requested permissions.
Scope []string `json:"scope"`
// Mapper specifies the JSONNet code snippet which uses the OpenID Connect Provider's data (e.g. GitHub or Google
// profile information) to hydrate the identity's data.
//
// It can be either a URL (file://, http(s)://, base64://) or an inline JSONNet code snippet.
Mapper string `json:"mapper_url"`
// RequestedClaims is a string encoded json object that specifies claims and optionally their properties that should be
// included in the id_token or returned from the UserInfo Endpoint.
//
// More information: https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
RequestedClaims json.RawMessage `json:"requested_claims"`
// An optional organization ID that this provider belongs to.
// This parameter is only effective in the Ory Network.
OrganizationID string `json:"organization_id"`
// AdditionalIDTokenAudiences is a list of additional audiences allowed in the ID Token.
// This is only relevant in OIDC flows that submit an IDToken instead of using the callback from the OIDC provider.
AdditionalIDTokenAudiences []string `json:"additional_id_token_audiences"`
// ClaimsSource is a flag which controls where the claims are taken from when
// using the generic provider. Can be either `userinfo` (calls the userinfo
// endpoint to get the claims) or `id_token` (takes the claims from the id
// token). It defaults to `id_token`.
ClaimsSource string `json:"claims_source"`
// PKCE controls if the OpenID Connect OAuth2 flow should use PKCE (Proof Key for Code Exchange).
// Possible values are: `auto` (default), `never`, `force`.
// - `auto`: PKCE is used if the provider supports it. Requires setting `issuer_url`.
// - `never`: Disable PKCE entirely for this provider, even if the provider advertises support for it.
// - `force`: Always use PKCE, even if the provider does not advertise support for it. OAuth2 flows will fail if the provider does not support PKCE.
// IMPORTANT: If you set this to `force`, you must whitelist a different return URL for your OAuth2 client in the provider's configuration.
// Instead of <base-url>/self-service/methods/oidc/callback/<provider>, you must use <base-url>/self-service/methods/oidc/callback
// (Note the missing <provider> path segment and no trailing slash).
PKCE string `json:"pkce"`
// FedCMConfigURL is the URL to the FedCM IdP configuration file.
// This is only effective in the Ory Network.
FedCMConfigURL string `json:"fedcm_config_url"`
// NetIDTokenOriginHeader contains the orgin header to be used when exchanging a
// NetID FedCM token for an ID token.
NetIDTokenOriginHeader string `json:"net_id_token_origin_header"`
// AccountLinkingMode controls how account conflicts are resolved for this provider.
// Possible values: "confirm_with_existing_credential" (default), "automatic".
// This is only effective in the Ory Network.
AccountLinkingMode string `json:"account_linking_mode,omitempty"`
// UpdateIdentityOnLogin controls whether the identity is updated from
// OIDC claims on each login.
//
// Possible values:
// - "never" (default): the identity is not updated on login.
// - "automatic": re-runs the Jsonnet claims mapper on every OIDC login
// and updates the identity's traits and metadata automatically.
UpdateIdentityOnLogin string `json:"update_identity_on_login,omitempty"`
// AAL2ACRValues lists upstream OIDC `acr` claim values that elevate
// the resulting Kratos session to AAL2. When empty, the session AAL
// is always AAL1 regardless of the upstream `acr` claim.
AAL2ACRValues []string `json:"aal2_acr_values,omitempty"`
// AAL2AMRValues lists upstream OIDC `amr` claim values that elevate
// the resulting Kratos session to AAL2 when any of them appears in
// the upstream `amr` array. When empty, `amr` does not influence the
// session AAL.
AAL2AMRValues []string `json:"aal2_amr_values,omitempty"`
}
// AALForClaims returns the session AuthenticatorAssuranceLevel that the
// upstream OIDC response should be mapped to, based on the provider's
// AAL2ACRValues / AAL2AMRValues allowlists and the ACR / AMR claims
// reported by the upstream provider.
//
// The default is AAL1. AAL2 is only returned when either the upstream
// `acr` claim matches one of the configured AAL2ACRValues, or at least
// one of the upstream `amr` entries matches one of the configured
// AAL2AMRValues. An empty `acr` never matches, even if the allowlist
// contains an empty string.
func (c *Configuration) AALForClaims(claims *Claims) identity.AuthenticatorAssuranceLevel {
if claims == nil {
return identity.AuthenticatorAssuranceLevel1
}
if claims.ACR != "" && slices.Contains(c.AAL2ACRValues, claims.ACR) {
return identity.AuthenticatorAssuranceLevel2
}
for _, want := range c.AAL2AMRValues {
if slices.Contains(claims.AMR, want) {
return identity.AuthenticatorAssuranceLevel2
}
}
return identity.AuthenticatorAssuranceLevel1
}
func (p Configuration) Redir(public *url.URL) string {
if p.PKCE == "force" {
return urlx.AppendPaths(public, RouteCallbackGeneric).String()
}
if p.OrganizationID != "" {
route := RouteOrganizationCallback
route = strings.Replace(route, "{provider}", p.ID, 1)
route = strings.Replace(route, "{organization}", p.OrganizationID, 1)
return urlx.AppendPaths(public, route).String()
}
return urlx.AppendPaths(public, strings.Replace(RouteCallback, "{provider}", p.ID, 1)).String()
}
type ConfigurationCollection struct {
BaseRedirectURI string `json:"base_redirect_uri"`
Providers []Configuration `json:"providers"`
}
// !!! WARNING !!!
//
// If you add a provider here, please also add a test to
// provider_private_net_test.go
var supportedProviders = map[string]func(config *Configuration, reg Dependencies) Provider{
"generic": NewProviderGenericOIDC,
"google": NewProviderGoogle,
"github": NewProviderGitHub,
"github-app": NewProviderGitHubApp,
"gitlab": NewProviderGitLab,
"microsoft": NewProviderMicrosoft,
"discord": NewProviderDiscord,
"salesforce": NewProviderSalesforce,
"slack": NewProviderSlack,
"facebook": NewProviderFacebook,
"auth0": NewProviderAuth0,
"vk": NewProviderVK,
"yandex": NewProviderYandex,
"apple": NewProviderApple,
"spotify": NewProviderSpotify,
"netid": NewProviderNetID,
"dingtalk": NewProviderDingTalk,
"linkedin": NewProviderLinkedIn,
"linkedin_v2": NewProviderLinkedInV2,
"patreon": NewProviderPatreon,
"lark": NewProviderLark,
"x": NewProviderX,
"line": NewProviderLineV21,
"jackson": NewProviderJackson,
"fedcm-test": NewProviderTestFedcm,
"amazon": NewProviderAmazon,
"uaepass": NewProviderUAEPass,
}
func (c ConfigurationCollection) Provider(id string, reg Dependencies) (Provider, error) {
for _, p := range c.Providers {
if p.ID == id {
if f, ok := supportedProviders[p.Provider]; ok {
return f(&p, reg), nil
}
return nil, errors.Errorf("provider type %s is not supported, supported are: %v", p.Provider, maps.Keys(supportedProviders))
}
}
return nil, errors.WithStack(herodot.ErrNotFound().WithReasonf(`OpenID Connect Provider "%s" is unknown or has not been configured`, id))
}