Skip to content

OpenID Connect authentication

OpenID Connect authentication has been tested with Keycloak and Microsoft Entra ID. It should work with other OpenID Connect providers as well, as long as they support the authorization flow with PKCE and without a secret.

Keycloak

In Keycloak a new OpenID Connect client needs to be created. The client needs to be configured as follows, assuming the frontend is available at https://secobserve.example.com:

Keycloak client settings

Configuration parameters for SecObserve

Backend:

Environment variable Value
OIDC_AUTHORITY https://keycloak.example.com/realms/NAME_OF_REALM
OIDC_CLIENT_ID CLIENT_ID
OIDC_USERNAME preferred_username
OIDC_FIRST_NAME given_name
OIDC_LAST_NAME family_name
OIDC_EMAIL email
OIDC_GROUPS groups

Frontend:

Environment variable Value
OIDC_ENABLE true
OIDC_AUTHORITY https://keycloak.example.com/realms/NAME_OF_REALM
OIDC_CLIENT_ID CLIENT_ID
OIDC_REDIRECT_URI https://secobserve.example.com
OIDC_POST_LOGOUT_REDIRECT_URI https://secobserve.example.com
OIDC_PROMPT [no value]

Microsoft Entra ID

In Microsoft Entra ID, a new App registration needs to be created, with the redirect URI registered under the Single-page application (SPA) platform. A client secret is not needed.

Configuration parameters for SecObserve

Backend:

Environment variable Value
OIDC_AUTHORITY https://login.microsoftonline.com/TENANT_ID/v2.0
OIDC_CLIENT_ID CLIENT_ID
OIDC_USERNAME preferred_username
OIDC_FULL_NAME name
OIDC_EMAIL email
OIDC_GROUPS groups

Frontend:

Environment variable Value
OIDC_ENABLE true
OIDC_AUTHORITY https://login.microsoftonline.com/TENANT_ID/v2.0
OIDC_CLIENT_ID CLIENT_ID
OIDC_REDIRECT_URI https://secobserve.example.com
OIDC_POST_LOGOUT_REDIRECT_URI https://secobserve.example.com
OIDC_PROMPT [no value]

Customize the login dialog

If users should only be able to sign in with OpenID Connect, the login dialog can be customized to hide user and password fields. This can be done by setting the Disable user login option in the Settings dialog:

Disable user login

Then the login dialog will only show the Enterprise sign in button:

Enterprise sign in

If the user and password is needed to login, e.g. for a local admin user, #force_user_login can be added to the URL (like https://secobserve.example.com/#/login#force_user_login) to force the user and password fields to be shown.

Clock skew betwenn OIDC server and SecObserve backend

A time deviation between the OIDC server and the SecObserve backend cannot always be avoided. To prevent the verification of claims issued at, not before and expiry from failing because of it, the parameter OIDC clock skew can be set in the settings.

OIDC clock skew

Token renewal

The frontend authenticates against the backend with the id token and renews the tokens before they expire. For a reliable renewal, the OIDC provider has to fulfil some requirements:

  • Refresh tokens: The provider has to issue a refresh token. Depending on the provider, the refresh token grant has to be enabled for the client and/or the scope offline_access has to be added to OIDC_SCOPE. Without a refresh token, the frontend falls back to a renewal in a hidden iframe with prompt=none. This often fails because browsers block third-party cookies, and then users have to sign in again.
  • Id token on renewal: The provider has to return a new id token when the refresh token is used. Otherwise the old id token expires and users have to sign in again. In this case the frontend writes the warning OIDC token renewal did not provide a new id token to the browser console.

Whether a refresh token has been issued can be checked in the local storage of the browser: The entry oidc.user:<OIDC_AUTHORITY>:<OIDC_CLIENT_ID> must contain a refresh_token.

Providers with refresh token rotation accept every refresh token only once. The frontend makes sure that only one renewal runs at a time, even with several browser tabs open.

If the renewal fails nevertheless, users are sent to the OIDC provider to sign in again and return to the page they have been on. As long as their session at the OIDC provider is active, they don't need to enter anything.

Audience validation

By default SecObserve requires the aud claim of a token to be a single string that matches the OIDC client id exactly. This is the strictest interpretation and is recommended wherever the OIDC provider supports it.

Not all OIDC providers work that way. Some always issue aud as a list, even when it holds a single entry, and some add the ids of other applications to it. With such a provider the login itself succeeds, but every authenticated request fails with HTTP 401 and the backend logs Invalid claim format in token (strict).

For these providers the parameter OIDC strict audience can be switched off in the settings. The aud claim is then still validated, but a list is accepted as long as it contains the client id, which is the behaviour RFC 7519, section 4.1.3 describes.

User API tokens for users authenticated with OpenID Connect

Users authenticated with OpenID Connect have no password in SecObserve, so they cannot confirm a password when they create or revoke a user API token. Instead SecObserve requires a recent authentication at the OIDC provider as the proof of identity. The auth_time claim of the id token, which states when the user actually authenticated, must not be older than the parameter OIDC API token max authentication age in the settings. The default is 5 minutes, the value 0 switches the check off and lets any valid OIDC token create and revoke API tokens.

The auth_time claim deliberately does not move forward when the frontend silently renews its token, only a real authentication updates it. If the authentication is too old, the frontend offers to sign in again and sends the user to the OIDC provider with prompt=login and max_age=0. After the authentication the user returns to the same page and can create or revoke the API token.

The id token is a credential that is stored in the browser, so this makes an API token reachable for anyone who can read it. Keeping the maximum authentication age small limits the time window in which that is possible. The creation of every user API token is written to the log of the backend.

Providers that do not send auth_time

The auth_time claim is only required by OpenID Connect Core, section 3.1.3.6 if the authentication was requested with max_age or if the claim was requested as an essential claim. Not all providers send it in all cases:

  • Keycloak sends auth_time and honours prompt=login and max_age, no additional configuration is needed.
  • Okta documents auth_time as a base claim of the id token. It should be verified for the authorization server that is used.
  • Microsoft Entra ID does not send auth_time by default. It has to be added as an optional claim for id tokens in the token configuration of the app registration.

If the provider never sends auth_time, SecObserve answers requests to create or revoke a user API token with HTTP 403 and the code oidc_auth_time_missing. The frontend then offers to sign in again once and shows an error afterwards, to avoid an endless loop of redirects. For such a provider the parameter OIDC API token max authentication age has to be set to 0.