yeke.io · docs · enterprise

OIDC Login (SSO)

Connect an OIDC provider such as Keycloak or Entra ID with Enterprise. Users can sign in through SSO while local accounts remain available. This guide covers provider settings, the redirect URI and group mapping.

Overview

One more button on the login screen; the password path stays where it is.

The SSO button takes the user to the provider’s login page. YEKE never receives the password. After authentication, YEKE creates a session using the Authorization Code + PKCE flow.

The local username-and-password form does not disappear. That is not an oversight but an emergency access path: the install owner is always local, so local administrator login stays available when the provider is unreachable or misconfigured.

The SSO button is only drawn on the login screen when two conditions hold together: an enabled provider must be defined and the license must carry the Enterprise sso item. That item is shared with Active Directory / LDAP login — there is no new license flag, and both can be enabled at the same time.

Defining the provider

One provider is configured from the admin screen, and saving it really tests the connection.

FieldWhat it does
labelThe text on the login screen's button. It is the only name the user ever sees.
issuerThe provider's identity URL; https is required. It must match the issuer value in the provider's discovery document exactly — trailing slash included.
clientIdThe ID of the client you created for YEKE on the provider side.
clientSecretThe client secret; it is required. It is write-only: no response ever returns it, a response only says whether it is set.
caCertPemOptional. If the provider's certificate is signed by an internal CA, paste its PEM here. A certificate is not a secret, so it is stored unencrypted.
usernameClaimThe claim the username is read from. Default preferred_username; email is also selectable.
groupsClaimThe claim groups are read from. Default groups.
adminGroupOptional. When set, members of that group get the admin role on every login.
Extra scopesAny scopes you need to request from the provider beyond the defaults.
label             :  Corporate account
issuer            :  https://id.example.com/realms/corp
client id         :  yeke
client secret     :  (write-only)
username claim    :  preferred_username
groups claim      :  groups
admin group       :  yeke-admins

Before you save, the "Test connection" button really fetches the provider's discovery document, resolves the endpoints and writes them into the record. If the test fails, the reason shows up on screen; the record is still stored, but not enabled.

Only one provider can be enabled at a time.

A wrong client secret now shows up as IDP_CLIENT_REJECTED

If the provider rejects the client secret at the last step of sign-in, YEKE now shows its own error code for that — it used to report a generic "cannot reach identity provider" message. On Entra ID the most common cause is copying the Secret ID instead of the Value column: the column to copy is Value, not Secret ID. If the client ID is wrong, the error appears on Microsoft's sign-in page before the flow ever returns to YEKE (AADSTS700016).

The redirect URI

The address derives from YEKE's own public URL, not from the incoming request's headers.

The return address from the provider is built by appending /api/auth/oidc/callback to YEKE_PUBLIC_URL. That address has to be registered on the provider side exactly like this.

YEKE_PUBLIC_URL  :  https://yeke.example.com
redirect URI     :  https://yeke.example.com/api/auth/oidc/callback

Without YEKE_PUBLIC_URL, the configuration is refused

The redirect URI comes from YEKE_PUBLIC_URL, never from a request header. This setting is required; OIDC configuration is rejected when it is empty. Installation settings →

Keycloak treats only a trailing * as a wildcard

Register the exact redirect URI with your provider. Avoid a wildcard in the middle: for example, https://server:*/path will not match in Keycloak and produces invalid_redirect_uri.

Roles and Kubernetes group mapping

The group claim is written into the same mapping list as the directory side; there is no separate list for OIDC.

Roles can be derived from the directory

The provider record lets you optionally name an admin group (adminGroup). When set, a user's role is derived from the token's group claim on every login, and writing that user's role from the UI is refused — otherwise a manual edit would be silently overwritten by the next login. Leave it unset and the role is managed the usual way, from YEKE's user screen.

Kubernetes identity: the same list as the directory

The cluster rule plus personal binding model described on the Permissions and RBAC page still applies. The token's group claim is written into the same mapping list in the cluster identity rule: there is no separate list for LDAP and another for OIDC. One list carries both LDAP group DNs and OIDC's plain group names.

source group                                      Kubernetes group
CN=YEKE-Operators,OU=Groups,DC=example,DC=com  →  yeke:cluster-admins    (LDAP)
yeke-operators                                 →  yeke:cluster-admins    (OIDC)
3f2b9c14-8a71-4d0e-9c53-6b7a1e5d20f4           →  payments-oncall        (OIDC)

Keycloak: "full path" must be off in the group mapper

Keycloak's group mapper can emit the group's full path (/parent-group/child-group). If you want to write plain group names in the mapping list, that option has to be off — the plain name landing in the claim depends on it.

Entra ID emits GUIDs in the group claim

Entra ID puts a group's GUID, not its name, into the group claim; the value you write on the left side of a mapping row is that GUID. An optional label can be written on the row — a list of nothing but GUIDs becomes unreadable.

Registering an application in Entra ID

Before you can connect Microsoft Entra ID as a provider, you need to register an application on the Entra side: the application registration, the client secret, the admin group and the token's group setting are all covered step by step on the Entra ID SSO Setup page.

First login: automatic user creation and license seats

You do not pre-invite anyone from the provider into YEKE.

  • Just-in-time creation. A user who authenticates against the provider but has no YEKE record yet is created automatically on their first successful login.
  • It consumes a seat. An automatically created user consumes a license seat exactly like one created by hand. If the seat ceiling is reached, the login is refused with an explicit code.
  • The username comes from the claim. The name YEKE stores is the value of the claim you chose in usernameClaim; that is the name shown in the user list and the audit trail.
  • A login is refused if an account with the same name exists. If the incoming username collides with an existing local or LDAP account, the login stops with a loud error; the OIDC user is not silently attached to that account. Silent attachment falls into the account-takeover class.

Second factor

For an OIDC user, the authority over the second factor is the IdP.

  • An OIDC user cannot enroll YEKE's own TOTP. The provider decides who is asked for a second factor; YEKE does not open a second factor record for the same user.
  • Nothing changes for local accounts. YEKE's own second factor stays exactly as it is for local users.

Limits

The line between what exists today and what does not.

  • No SAML or SCIM. Everything on this page is about OIDC; SAML and SCIM remain in the demand-driven queue.
  • End-to-end Entra ID login was tested against a real tenant. Group object ID (GUID) → role and Kubernetes group mapping was part of the same test; this landed in 0.46.1 — earlier releases could not even register Entra ID as a provider. Still unverified: Entra's "groups overage" behavior for a user who belongs to many groups, and whether the user identity (sub) changes when an app registration is recreated.
  • A login is refused on Entra "groups overage". When a user belongs to too many groups, Entra ID does not emit the group claim at all. YEKE refuses the login in that case; it does not silently continue with an empty group set, because that path would leave the user without access and without any error.
  • One enabled provider at a time. There is no keeping more than one OIDC provider enabled simultaneously.
  • A YEKE session does not end when the IdP session does. There is no back-channel logout: YEKE holds its own session, and the provider's token is used only at login and never stored.
  • None of this works without a license. Provider configuration and OIDC login are refused with an explicit error without the Enterprise sso item; local login is never affected.

See what group mapping means on the RBAC side

Groups arriving from the provider flow into Kubernetes groups here — but the decision is still RBAC's. The directory path that feeds the same list lives on its own page.