Sign in with your identity provider
An App names an OpenID Connect provider; the config file says where it is.
auth: { providers: ['email', oidc('workforce')], signUp: { providers: [oidc('workforce')] }, // or { domains: ['contoso.com'] } roles: { underwriter: { read: true, commands: ['approve-loan'], from: { groups: ['2f1c…'] } } },},{ "name": "workforce", "kind": "oidc", "label": "Contoso", "issuer": "https://login.microsoftonline.com/<tenant id>/v2.0", "clientId": "<application id>", "clientSecret": "${WORKFORCE_CLIENT_SECRET}" }Register <public URL>/api/auth/callback/workforce at the provider. The entry
also takes scopes (default email profile), discovery (a metadata URL
other than <issuer>/.well-known/openid-configuration), verifiedEmails
(it asserts only verified addresses), mfa (the acr values that mean more
than one factor) and insecure (an http issuer on a trusted network). The
secret is only ever a ${VARIABLE}. The browser sees the label, nothing else.
Every sign-in is a code with PKCE, state and nonce; the ID token’s signature,
issuer, audience, azp, age (a minute of skew) and nonce are checked. A person
is the issuer’s subject, never an email. Only the ID token is kept.
Roles, sign-up and linking
Section titled “Roles, sign-up and linking”from: { <claim or dotted.path>: [values] }gives a role at every sign-in; roles without it stay as an administrator set them. Changes go to the account’s history; each value is a line of authority.lock. A sign-in that leaves no declared role is refused with a sentence. Not in a tenant App.signUp: 'invite'makes no account at a first sign-in,'open'does, and{ providers, domains }does through those providers, or for a verified email in those domains (both, when both are said).- An address links to an existing account only if verified (
email_verified, orverifiedEmails). An account whose own address was never verified loses its password, other links and sessions when a verified sign-in claims it.
Step-up
Section titled “Step-up”Opening a support session needs a sign-in from the last five minutes: for a
provider, when it authenticated the person (auth_time). With mfa listed,
only a sign-in with more than one factor counts (amr, or a listed acr).
Otherwise the dialog offers Confirm at your sign-in provider (prompt=login,
max_age=0, acr_values).
A tenant’s own provider
Section titled “A tenant’s own provider”oidc.tenants() offers Sign in with your work email: an entry with
"tenant": "north", "domains": ["north-motors.com"] is that tenant’s. It is set
in the deployment’s config file by whoever runs the platform, never by a
tenant or a route; it signs in only verified addresses in its domains, gives
no membership (the tenant store does), and a domain is one tenant’s.
Recipes
Section titled “Recipes”- Entra ID: issuer
https://login.microsoftonline.com/<tenant id>/v2.0; add theemailoptional claim;from: { groups: [...] }or{ roles: [...] }. It sends noemail_verified:verifiedEmailsonly for a single-tenant app. - Entra External ID: issuer
https://<tenant id>.ciamlogin.com/<tenant id>/v2.0. - Azure AD B2C: a user flow is its issuer. Pick the token issuer with the
policy,
https://<name>.b2clogin.com/tfp/<tenant id>/<policy>/v2.0/, and setdiscoverytohttps://<name>.b2clogin.com/<name>.onmicrosoft.com/<policy>/v2.0/.well-known/openid-configuration. - Okta: issuer
https://<org>.okta.com/oauth2/default; add agroupsclaim;"mfa": ["urn:okta:loa:2fa:any"]. - Keycloak: issuer
https://<host>/realms/<realm>; turn on Add to ID token in the roles mapper, thenfrom: { 'realm_access.roles': [...] }.