Sign in with your identity provider
Sign people in through an OpenID Connect or SAML 2.0 provider (Entra ID, Okta, ADFS, Keycloak) and give them roles from its claims.
auth: { providers: ['email', oidc('workforce')], signUp: { providers: [oidc('workforce')] }, // or { domains: ['contoso.com'] } roles: { underwriter: { read: true, commands: ['approve-loan'], claims: { groups: ['2f1c…'] } } },},{ "name": "workforce", "kind": "oidc", "label": "Contoso", "issuer": "https://login.microsoftonline.com/<tenant id>/v2.0", "clientId": "<application id>", "clientSecret": "${WORKFORCE_CLIENT_SECRET}" }The App names the provider and tablewalk.json says where it is. Register <public URL>/api/auth/callback/workforce at the provider.
What you’ll see
Section titled “What you’ll see”- Continue with Contoso on the sign-in card: the entry’s
labelis all the browser learns of it. - An underwriter’s role given at every sign-in from the
groupsclaim, and recorded in the account’s history.
When to use it, and when not
Section titled “When to use it, and when not”- Use a provider when your organization already signs people in and decides their groups; use passwords for a small team without one.
- Use
claimswhen the provider should decide roles; leave it off and an administrator sets roles by hand.
Options
Section titled “Options”| Entry key | What it does | Default |
|---|---|---|
issuer, clientId, clientSecret |
The provider; the secret is only ever a ${VARIABLE}, and a literal one is refused |
required |
scopes |
What is asked for | email profile |
discovery |
A metadata URL other than <issuer>/.well-known/openid-configuration |
derived |
verifiedEmails |
The provider asserts only verified addresses | false |
mfa |
The acr values that mean more than one factor |
none |
insecure |
Allows an http issuer on a trusted network |
false |
backchannelLogout |
The provider may end the sessions it opened (below) | false |
Every sign-in is a code flow with PKCE, state and nonce. The server checks the ID token’s signature, issuer, audience, azp, age (a minute of skew) and nonce. A person is the issuer’s subject, never an email, and only the ID token is kept.
- Roles.
claims: { <claim or dotted.path>: [values] }gives a role at each sign-in, and counts only in a session that provider opened: a password session of the same account keeps only the roles set by hand. A sign-in that leaves no declared role is refused. - Sign-up.
'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. - Linking. An address links to an existing account only if verified (
email_verified, orverifiedEmails). - Step-up. Opening a support session needs a sign-in from the last five minutes; with
mfa, one with more than one factor. - A tenant’s own.
oidc.tenants()offers Sign in with your work email; an entry with"tenant": "north", "domains": ["north-motors.com"]is that tenant’s, set by whoever runs the platform. It gives no membership. - SAML 2.0.
saml('corp')and a"kind": "saml"entry sign in the same way: SAML 2.0 sign-in. A directory that adds and removes people is SCIM provisioning. - Back-channel logout. With
"backchannelLogout": true, register<public URL>/api/auth/backchannel-logout/<name>at the provider (startup prints it). A signed logout token ends the sessions that provider’s session opened, bysidor by subject; API tokens are the account’s and stay.
Recipes: Entra ID issuer https://login.microsoftonline.com/<tenant id>/v2.0, add the email optional claim, and use verifiedEmails only for a single-tenant app. Entra External ID https://<tenant id>.ciamlogin.com/<tenant id>/v2.0.
Azure AD B2C https://<name>.b2clogin.com/tfp/<tenant id>/<policy>/v2.0/ with discovery set to https://<name>.b2clogin.com/<name>.onmicrosoft.com/<policy>/v2.0/.well-known/openid-configuration.
Okta https://<org>.okta.com/oauth2/default, a groups claim, "mfa": ["urn:okta:loa:2fa:any"]. Keycloak https://<host>/realms/<realm>, Add to ID token in the roles mapper, then claims: { 'realm_access.roles': [...] }.
Common mistakes
Section titled “Common mistakes”[identity-provider-unknown]or[identity-provider-kind]→ add an entry with that name totablewalk.json:"kind": "oidc"foroidc('…'),"kind": "saml"forsaml('…').[claim-without-provider]: a role hasclaimsand nooidc('…')orsaml('…')provider → add the provider, or dropclaims.[claim-grants-nothing]→ give the role a grant, or drop it.[claim-in-tenant-app]→ in a tenant App, grant the membership in the tenant store instead.
Related
Section titled “Related”- Sign-in: the other providers, accounts and the first administrator.
- Roles and field access: what a role from claims grants.
- Several Apps in one server: one provider shared by a suite.