OIDC Integration

OIDC integration lets users authenticate against an external identity provider (Keycloak by default) instead of, or in addition to, the built-in CouchDB-backed login.

Admin-api validates the OIDC access token, maps the token claims to an OpenServerless namespace and returns the same AUTH/NAMESPACE shaped payload produced by the classic /system/api/v1/auth login, so existing clients (ops, the console, …) don't need to know whether the user logged in with a password or via SSO.

Three login styles are supported:

styledescription
direct tokenThe caller already holds an OIDC access token (e.g. from a browser/PKCE flow) and posts it directly.
device flowadmin-api drives an OAuth2 Device Authorization flow on behalf of a CLI/headless client; the OIDC tokens never reach the client.
password grantadmin-api exchanges a username/password directly with the OIDC provider (Resource Owner Password Credentials grant); useful for trusted CLI/automation flows.

In all three cases, the access token is verified locally (RS256 signature against the provider's JWKS, issuer, audience, expiry and optional group membership) before any namespace mapping happens — see openserverless/common/oidc_validator.py.

Namespace mapping

The preferred_username claim (or whatever OIDC_USERNAME_CLAIM points to) identifies the external identity. It is turned into an OpenServerless namespace by openserverless/common/sso_namespace.py using this precedence:

  1. If OIDC_NAMESPACE_CLAIM is set and the claim value is a valid namespace, use it as-is.
  2. If SSO_NAMESPACE_PRESERVE_VALID is enabled (default) and the external username is already a valid namespace, use it as-is.
  3. Otherwise, normalize the external username (lowercase, strip invalid characters, pad if too short) and append a stable hash suffix derived from iss + sub + username, so the mapping collision-resistant and repeatable across logins.

If a namespace cannot be provisioned automatically, an existing WhiskUser can be bound to an SSO identity manually by an admin, or auto-provisioning can be enabled (see below).

Auto-provisioning

By default, an OIDC login only succeeds if a WhiskUser for the resolved namespace already exists. Setting SSO_AUTOPROVISION_ON_LOGIN=true allows admin-api to create the WhiskUser custom resource on first login (requires an email claim), then poll CouchDB until the namespace metadata becomes available.

A namespace can be locked out of SSO login (e.g. to force a manual password reset) by setting the openserverless.apache.org/sso-disabled annotation to true on its WhiskUser.

Configuration

All configuration is read from environment variables of the admin-api pod.

variablerequireddefaultdescription
OIDC_ISSUER_URLyesExpected iss claim / base URL of the realm, also used to derive the device-authorization and token endpoints.
OIDC_JWKS_URLyesJWKS endpoint used to fetch the provider's signing keys.
OIDC_AUDIENCEyesExpected aud claim of the access token.
OIDC_CLIENT_IDnovalue of OIDC_AUDIENCEClient id used for the device and password grant flows.
OIDC_CLIENT_SECRETnoClient secret, if the OIDC client is confidential.
OIDC_USERNAME_CLAIMnopreferred_usernameClaim used as the external username.
OIDC_NAMESPACE_CLAIMnoClaim to use directly as the namespace, when present and valid.
OIDC_GROUPS_CLAIMnogroupsClaim holding the user's group memberships.
OIDC_REQUIRED_GROUPnoIf set, tokens without this group in OIDC_GROUPS_CLAIM are rejected with 403.
OIDC_CLOCK_LEEWAY_SECONDSno30Clock skew tolerance applied to exp/nbf validation.
OIDC_PROVIDERnokeycloakRecorded on auto-provisioned WhiskUsers for traceability.
OIDC_DEVICE_AUTHORIZATION_URLno${OIDC_ISSUER_URL}/protocol/openid-connect/auth/deviceDevice Authorization endpoint.
OIDC_TOKEN_URLno${OIDC_ISSUER_URL}/protocol/openid-connect/tokenToken endpoint used by the device and password flows.
OIDC_DEVICE_SCOPEnoopenid email profileScope requested when starting a device flow.
OIDC_PASSWORD_SCOPEnoopenid email profileScope requested for the password grant.
SSO_NAMESPACE_PRESERVE_VALIDnotrueKeep the external username as namespace when it is already a valid namespace.
SSO_NAMESPACE_HASH_LENGTHno8 (clamped 6-16)Length of the collision-avoidance hash suffix appended to normalized namespaces.
SSO_NAMESPACE_MAX_LENGTHno61 (clamped 13-61)Maximum length of a generated namespace.
SSO_AUTOPROVISION_ON_LOGINnofalseCreate a WhiskUser automatically on first successful OIDC login.
SSO_AUTOPROVISION_DEFAULT_SERVICESnoallWhen set to all, enables redis/mongodb/postgres/object-storage/milvus on the provisioned WhiskUser.
SSO_AUTOPROVISION_STORAGE_QUOTAnoautoObject-storage quota assigned to auto-provisioned users.
SSO_AUTOPROVISION_TIMEOUT_SECONDSno120How long admin-api waits for the provisioned namespace metadata to appear.
SSO_AUTOPROVISION_POLL_SECONDSno2Poll interval while waiting for provisioning to complete.

NOTE: OIDC_ISSUER_URL, OIDC_JWKS_URL and OIDC_AUDIENCE are always required; the device and password grant flows additionally rely on OIDC_ISSUER_URL to derive their endpoints unless OIDC_DEVICE_AUTHORIZATION_URL / OIDC_TOKEN_URL are overridden explicitly.

A namespace can also opt out of SSO entirely by setting the openserverless.apache.org/sso-disabled: "true" annotation on its WhiskUser.

Endpoints

POST /system/api/v1/auth/oidc - Authenticate with an OIDC access token, passed either as a Bearer Authorization header or as access_token in the JSON body.

POST /system/api/v1/auth/oidc/device/start - Start a backend-managed OAuth2 Device Authorization flow. Returns an opaque flow_id plus the user_code/verification_uri to show to the user; no OIDC token is exposed to the caller.

POST /system/api/v1/auth/oidc/device/poll - Poll a device flow started above, using the flow_id. Returns 202 while the user hasn't completed the login at the identity provider yet, and the OpenServerless login payload once it succeeds.

POST /system/api/v1/auth/oidc/password - Authenticate with a username/password using the OIDC Resource Owner Password Credentials grant. The password and any OIDC tokens are never returned to the caller.

Unlike /system/api/v1/auth, none of the OIDC endpoints require a pre-existing wsk token: the OIDC token (or credentials) themselves are the proof of identity.

Examples

Direct token login

POST /system/api/v1/auth/oidc
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ii4uLiJ9...

Device flow

POST /system/api/v1/auth/oidc/device/start
{
  "namespace": "myuser"
}
200 OK
{
  "flow_id": "u9F1...opaque...",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://keycloak.example.test/device",
  "verification_uri_complete": "https://keycloak.example.test/device?user_code=ABCD-EFGH",
  "expires_in": 600,
  "interval": 5
}

Show verification_uri_complete (or user_code + verification_uri) to the user, then poll:

POST /system/api/v1/auth/oidc/device/poll
{
  "flow_id": "u9F1...opaque..."
}

Password grant login

POST /system/api/v1/auth/oidc/password
{
  "username": "myuser",
  "password": "secret",
  "namespace": "myuser"
}

The optional namespace field in the device/password flows lets the caller assert which namespace it expects to log into; if the token resolves to a different namespace, admin-api returns 403 rather than logging into the wrong workspace.

Useful Links