Kubesense

Okta OIDC

Overview

This article describes how to set up OpenID Connect (OIDC) authentication for KubeSense using Okta.

The browser performs the OAuth 2.0 authorization-code flow with PKCE against Okta, then posts the resulting ID token to KubeSense, which verifies its signature against Okta's published keys before establishing a session.

info: Okta supports both OIDC and SAML. Either works — SAML is the more common enterprise choice and additionally supports group-to-role mapping. See Okta SAML if you would rather use it.

Prerequisites

  • An Okta organization with super administrator access
  • A KubeSense deployment reachable at a public HTTPS URL (e.g. https://kubesense.example.com)
  • The ability to run helm upgrade against the deployment

Step 1: Create the OIDC app in Okta

  1. In the Okta Admin Console, go to ApplicationsApplications
  2. Click Create App Integration
  3. Select OIDC - OpenID Connect, then Single-Page Application, and click Next
  4. Configure:
FieldValue
App integration nameKubeSense
Grant typeAuthorization Code (PKCE is implied for SPAs)
Sign-in redirect URIshttps://<KUBESENSE_DOMAIN>/login/callback
Sign-out redirect URIshttps://<KUBESENSE_DOMAIN>/login
Controlled accessChoose who may use the app
  1. Click Save, then copy the Client ID from the app's General tab

warning: The sign-in redirect URI must end in /login/callback, not /login. It must also include the scheme. A mismatch produces redirect_uri errors from Okta before the user ever reaches KubeSense.

Select Single-Page Application, not Web Application: KubeSense holds no client secret, and Okta rejects a confidential-client configuration used from a browser.

Step 2: Grant the app in the authorization server policy

This step is easy to miss and produces a confusing error if skipped.

  1. Go to SecurityAPIAuthorization Servers
  2. Open the authorization server you intend to use — usually default
  3. Open the Access Policies tab
  4. Ensure a policy exists with a rule that applies to your app:
    • Assigned to: All clients, or explicitly include the KubeSense app
    • Grant type: Authorization Code
    • Scopes: openid, profile, email
  5. Save

warning: Without a matching policy rule, Okta returns 400 Bad Request — Policy evaluation failed for this request with error code access_denied at the authorization endpoint. This happens before any token is issued, so nothing appears in the KubeSense logs.

Note the Issuer URI shown on the authorization server page — you need it in Step 3. It is either:

  • Custom authorization server: https://<your-org>.okta.com/oauth2/default
  • Org authorization server: https://<your-org>.okta.com

KubeSense resolves signing keys through OIDC discovery, so both layouts work.

Step 3: Configure KubeSense via Helm values

api:
  # The API validates the ID token's `iss` and `aud` against these values and
  # fetches the signing keys from this issuer's OIDC discovery document.
  OKTA_ISSUER: "https://<your-org>.okta.com/oauth2/default"
  OKTA_CLIENT_ID: "<client-id-from-step-1>"

webapp:
  okta:
    enabled: true
    issuer: "https://<your-org>.okta.com/oauth2/default"
    client_id: "<client-id-from-step-1>"

warning: The issuer and client ID appear twice — once for the API and once for the webapp — and they must be identical. If they differ, the browser obtains a token from one Okta app and the API validates it against another, which fails with User email validation failed.

Apply with:

helm upgrade kubesense ./charts/kubesense-server -f values.yaml

Configuration reference

API environment variables

VariableDescription
OKTA_OAUTH2_ISSUERAuthorization server issuer. Rendered from api.OKTA_ISSUER.
OKTA_CLIENT_IDApplication client ID. The ID token's aud is validated against this.
OKTA_API_AUDIENCELegacy alias for OKTA_CLIENT_ID, still honoured.

Webapp environment variables

VariableDescription
ENABLE_OKTA_AUTHtrue renders the "Sign In with Okta" button
OKTA_ISSUERAuthorization server issuer — must match the API
OKTA_CLIENT_IDClient ID — must match the API

Step 4: Verify

  1. Open https://<KUBESENSE_DOMAIN>/login in a private browser window
  2. Click Sign In with Okta
  3. Authenticate with your Okta account
  4. You should land on the KubeSense dashboard

New users are provisioned automatically on first login with the User role.

How tokens are validated

Understanding this makes the errors below easier to read. On every sign-in the API:

  1. Resolves the JWKS endpoint from <issuer>/.well-known/openid-configuration
  2. Verifies the ID token's RSA signature against the published key matching the token's kid, refetching once if the key is unknown (so Okta key rotation is transparent)
  3. Rejects any token not signed with RSA, which blocks algorithm-confusion attacks
  4. Validates iss, aud and exp
  5. Rejects a token whose email_verified claim is explicitly false
  6. Reads the account's email from the email claim, falling back to preferred_username when it contains an @

A token with no usable email is rejected rather than provisioning an account under an opaque identifier.

info: The OIDC nonce is validated in the browser by the Okta SDK before the token is submitted. The server cannot re-check it, since only the page that initiated the flow knows the expected value.

Scopes and claims

KubeSense requests openid, profile and email.

  • email supplies the account identity and is required
  • profile supplies name, used for the display name. If absent, the email's local part is used instead.

Single Logout

Signing out of KubeSense also calls Okta's signOut(), ending the Okta session. Note that this path does not currently invalidate the server-side KubeSense session record; the session expires on its own.

Troubleshooting

SymptomCauseFix
400 Bad Request — Policy evaluation failed, access_deniedNo authorization server policy rule covers the appComplete Step 2
Okta redirect_uri errorSign-in redirect URI mismatchMust be exactly https://<domain>/login/callback, including scheme
400 User email validation failedID token failed verificationReal reason is in the API logs under Error validating token from provider:
Logs show signing key not found for key IDThe token came from a different Okta org or app than the API expectsMake OKTA_ISSUER identical for the webapp and the API. The logged error names the issuer actually used.
Logs show 'iss' value doesn't matchIssuer mismatchCheck for a trailing slash, or /oauth2/default present on one side only
Logs show 'aud' value doesn't matchClient ID mismatchMake the webapp and API client IDs identical
Logs show okta id token has no email claimemail scope not grantedAdd email to the authorization server policy rule's scopes
Logs show okta account email is not verifiedOkta reports email_verified: falseVerify the user's email in Okta
Logs show OKTA_OAUTH2_ISSUER is not setEnvironment variable missingConfirm api.OKTA_ISSUER is set and the pod was restarted
400 Email has already been takenThe email already exists with a different sign-in methodThe account was created via password or SAML. Use a different account, or change that user's auth_type/auth_provider.
Spinner never leaves /login/callbackLogin failed after the Okta redirectCheck for a toast message and the API logs; the underlying failure is one of the rows above