<issuer>/.well-known/openid-configuration). It runs the authorization-code flow, verifies the ID token, finds or creates the account, and starts the same session a password sign-in starts, so everything after sign-in (roles, bindings, inference tokens) works as for local accounts. SSO is not license-gated.
How a sign-in runs
- The admin UI sends the browser to
GET /api/auth/oidc/start, which redirects to the provider. - The provider redirects back to
https://<control host>/auth/callback, the redirect URL you register with it. (/api/auth/oidc/callbackis served too, for providers registered with that path.) - Relay exchanges the code, verifies the ID token, and matches the identity (issuer and subject) to an account: one that already has it, else a SCIM-provisioned account to link, else a new account when registration is open.
- Relay sets the
relay_sessioncookie and redirects to the post-login URL.
Configure it
Use either theauth:oidc settings section or environment variables. The environment wins when WYOLET_AUTH_MODE=oidc is set.
With the settings section
Put the client secret in an environment variable whose name starts withRELAY_OIDC_ (or WYOLET_OIDC_) and restart relay with it, then enable the section. Only an admin may write it.
https unless RELAY_COOKIE_SECURE=false. A stored section that breaks these rules is read as disabled and logged at startup; fix it and write the section again.
With environment variables
WYOLET_AUTH_MODE=oidc turns sign-in on from the environment alone, without a database write. Relay refuses to start if a required variable is missing or invalid.
Scopes (
openid profile email) and the groups claim (groups) take their defaults in this mode.
The issuer
Set the issuer to theissuer value of the provider’s discovery document. A configured issuer that differs from it only by a trailing slash is accepted, and accounts are matched with or without the slash; ID tokens must carry the document’s issuer exactly.
Registration
Withregistration: "open", a first sign-in by an unknown identity creates an account. Its username comes from preferred_username, else the part of the email before @, else user, with a numeric suffix when taken. The account gets no role. If another account already has the sign-in’s email, the sign-in is refused (email_in_use): linking a sign-in to an existing account is an administrator’s decision, never an email match.
With registration: "closed", only identities that already have an account, or that link to a SCIM-provisioned one, can sign in.
Groups
Relay reads the user’s groups from the ID token claim named bygroupsClaim (default groups; it must be an array of strings) at every sign-in. Each group becomes a subject the user acts under, so a RoleBinding that names the group by name applies to them, as it does for a local Group of the same name; see Groups. Names starting with system: are ignored, because relay reserves them. Set groupsClaim to "" when the provider asserts none.
The groups live in the session, not on the account: they change at the next sign-in, and an inference token minted in that session carries them until it expires. Under RELAY_AUTHZ=single, groups have no effect.
SCIM
To have the identity provider create and deactivate accounts ahead of sign-in, enable SCIM provisioning. A provisioned account has no sign-in identity until its user’s first OIDC sign-in links it, matched on theauth:scim section’s linkClaim.
Returning to an application
GET /api/auth/oidc/start takes an optional return_to: an absolute http or https URL the browser goes to after sign-in instead of the post-login URL. Its origin (scheme, host and port) must be one of: the origin of the redirect URL, the origin of the post-login URL when that is absolute, an entry of RELAY_CONTROL_ALLOW_ORIGINS, or the origin the start request reached. That last origin is https only over TLS, or when the peer is in RELAY_TRUSTED_PROXIES and sends X-Forwarded-Proto: https. Any other return_to is refused with 400 and code invalid_return_to.
Errors
When sign-in fails after areturn_to was accepted, the browser is redirected there with error=<code> added to its query. Without one, the callback answers {"error":{"type":"authentication_error","code":"<code>","message":"..."}} with the status below. Refused sign-ins are recorded in the audit log as denied auth.login events.
Provider notes
Zitadel- Turn on User Info inside ID Token (
idTokenUserinfoAssertion) for the application. Without it the ID token carries no email or username, and new accounts get generic usernames (user,user-2, …). - Zitadel has no flat
groupsclaim. Add an Action that collects the role keys of the user’s grants (ctx.v1.user.grants) and sets them as agroupsclaim, and attach it to the Complement Token flow on both the Pre Userinfo creation and Pre access token creation triggers.
authParams; they are added to the authorization URL as query parameters.