Skip to content

SSO (SAML / OIDC)

The Telovix Console supports OIDC (OpenID Connect) for single sign-on. The provider_kind field selects named variants that adjust the authorization flow for specific identity providers including Okta, Azure AD, Google Workspace, and generic OIDC.

SSO configuration requires the admin role. The client_secret is encrypted at rest using AES-256-GCM and is never returned after saving.

Prerequisites

  • admin role
  • IdP application registered with callback URL shown in Settings > Security > SSO
  • Client ID and client secret from IdP

Supported provider kinds

provider_kind valueIdentity providerExtra config
entraMicrosoft Entra ID (Azure AD)tenant_id: Entra tenant ID or domain
oktaOkta(none required)
googleGoogle Workspacehd: Workspace domain (e.g., example.com)
(any string)Generic OIDC-compliant provider(none required)

All variants use OIDC authorization code flow with PKCE. The provider_kind value affects which additional scopes and parameters are added to the authorization URL:

  • entra: adds offline_access scope (required for refresh tokens in Entra)
  • okta: adds groups scope (exposes group membership claims)
  • google: adds hd parameter as a login hint; enforces the hd domain server-side using the email claim

For any other provider_kind string, only the standard openid, email, and profile scopes are requested.


How the OIDC flow works

  1. Admin configures SSO via Settings > Security > SSO.
  2. The Console fetches OIDC provider metadata via OIDC discovery ({issuer_url}/.well-known/openid-configuration). Redirects are disabled on the discovery HTTP client.
  3. When a user initiates SSO login, the Console generates a PKCE challenge and CSRF token, stores pending state in console_sso_pending (expires in 10 minutes), and redirects the user to the IdP authorization URL.
  4. The IdP authenticates the user and redirects back to the Console SSO callback URL with the authorization code.
  5. The Console looks up the pending state (consumed atomically, one-time use even on expiry), exchanges the code for tokens, and verifies the ID token (issuer, audience, expiry, nonce, signature).
  6. The Console extracts the email and sub (subject) claims from the verified ID token.
  7. A Console user account is located or provisioned (see user provisioning below).
  8. The Console creates a session for the user.

The redirect URI is always the callback URL shown in Settings > Security > SSO. It is not accepted from client requests.


User provisioning

When a user logs in via SSO, the Console follows this lookup sequence:

  1. Match by stable identity: look up by (sso_provider, sso_subject). If found, update last_login_at and return the existing account.
  2. Match by email: if no subject match found, look up by email address.
    • If the email exists with no SSO link yet: link the existing account to this SSO identity.
    • If the email exists but is linked to a different SSO provider: reject with sso_account_conflict error.
    • If the email does not exist: create a new account.
  3. New account default role: new accounts created via SSO receive the analyst role. Admins must promote users to higher roles manually after first login.

The sub (subject) claim is used as the stable subject identifier across all providers. For Microsoft Entra, the oid claim is more stable across applications but requires custom claim configuration in the current implementation.


Configuring SSO in the Console

In the Console, go to Settings > Security > SSO to view, set, or clear the SSO configuration.

The Console presents these configuration fields:

FieldRequiredDescription
enabledYesWhether SSO is active
provider_kindYesProvider variant string
provider_labelYesLabel shown on the login button
client_idYesOIDC client ID from your IdP application
client_secretNoOIDC client secret. Leave blank to keep the current secret. Clear to remove it.
issuer_urlYesOIDC issuer URL. Must use HTTPS (localhost may use HTTP for development).
extra_configNoProvider-specific JSON object. Allowed keys: tenant_id, hd.
SSO configuration form showing provider kind selector, provider label, client ID field, client secret field, issuer URL, and extra config area.
SSO configuration form showing provider kind selector, provider label, client ID field, client secret field, issuer URL, and extra config area. Click to enlarge

extra_config allowed keys:

KeyUsed byDescription
tenant_identraEntra tenant ID or domain (alphanumeric, hyphens, dots; max 255 chars)
hdgoogleGoogle Workspace domain restriction. Enforced server-side using the email claim.

No other extra_config keys are accepted; the Console rejects unknown keys.

The redirect URI is computed server-side and displayed in the configuration view after saving. Register this exact URI in your IdP application.


Security properties

PKCE: All SSO flows use PKCE (Proof Key for Code Exchange). The code verifier is stored in the database as pending state and consumed once on callback, preventing authorization code injection attacks.

CSRF token: The Console generates a CSRF token per authorization request, stores it as pending state, and verifies it on callback.

Pending state expiry: Pending state rows expire after 10 minutes (set via database default). Expired state is consumed and discarded on callback, preventing replay of stale pending state.

One-time pending consumption: The consume_sso_pending function deletes the row atomically using DELETE ... RETURNING. Even if the callback handler errors after consumption, the state cannot be replayed.

Client secret encryption: The client_secret is encrypted at rest using AES-256-GCM with a 32-byte key derived from the Console's unique identifier via HMAC-SHA256 with context string "telovix-sso-encryption-v1". The key is deterministic: the same Console ID always produces the same key.

ID token verification: The library verifies iss, aud, exp, iat, nonce, and JWS signature on the ID token before extracting any claims.

SSRF protection: Both the OIDC discovery HTTP client and the token exchange HTTP client have redirects disabled.

Google domain enforcement: The hd parameter in the authorization URL is advisory. The Console enforces domain restriction server-side by comparing the email domain in the verified ID token against the configured hd value.


Configuring common identity providers

Microsoft Entra ID (Azure AD)

  1. Register an application in the Azure portal.
  2. Add the callback URL shown in Settings > Security > SSO as the allowed redirect URI in your IdP.
  3. Create a client secret.
  4. Note the Tenant ID, Client ID, and Client Secret.
  5. In the Console, go to Settings > Security > SSO and enter:
json
{
  "provider_kind": "entra",
  "provider_label": "Sign in with Azure AD",
  "client_id": "<application-client-id>",
  "client_secret": "<client-secret>",
  "issuer_url": "https://login.microsoftonline.com/<tenant-id>/v2.0",
  "extra_config": { "tenant_id": "<tenant-id>" }
}

Okta

  1. Create an OIDC Web Application in Okta.
  2. Add the callback URL shown in Settings > Security > SSO.
  3. Note the Client ID, Client Secret, and Okta domain.
  4. In the Console, go to Settings > Security > SSO and enter:
json
{
  "provider_kind": "okta",
  "provider_label": "Sign in with Okta",
  "client_id": "<client-id>",
  "client_secret": "<client-secret>",
  "issuer_url": "https://<your-okta-domain>/oauth2/default"
}

Google Workspace

  1. Create an OAuth 2.0 Client ID in Google Cloud Console.
  2. Add the callback URL shown in Settings > Security > SSO.
  3. In the Console, go to Settings > Security > SSO and enter:
json
{
  "provider_kind": "google",
  "provider_label": "Sign in with Google",
  "client_id": "<client-id>",
  "client_secret": "<client-secret>",
  "issuer_url": "https://accounts.google.com",
  "extra_config": { "hd": "yourdomain.com" }
}

The hd field restricts sign-in to accounts from the specified Google Workspace domain. If a user authenticates from a different domain, the Console rejects the login even if Google accepted the credentials.


Operational guidance

Role assignment after first login: New SSO users receive the analyst role. Review and promote users to operator, sensor_owner, or admin roles as needed after their first login. There is no automatic role mapping from IdP groups in the current implementation.

Disabling local passwords: The Console does not block local password authentication when SSO is enabled. If your security policy requires exclusive SSO access, disable local user accounts manually after provisioning them via SSO.

Break-glass access: Keep at least one local admin account with a strong password as a break-glass path. If the IdP becomes unavailable, SSO will fail and the Console will be inaccessible without a local login path.

Changing the Console base URL: The redirect URI is computed from the configured base URL. If you change the Console base URL in Console Settings, update the registered callback URL in your IdP application to match.


Further reading

Released under the Telovix Commercial License.