Okta

Wiring Okta as Flux's OIDC identity provider — authorization servers, audience handling, and the minimal Flux config.

Okta is a hosted OIDC provider built around the concept of authorization servers: each one has its own issuer URL, audience, and signing keys. Flux talks to Okta the same way it talks to any other OIDC IdP: discovery, JWKS, RS256-signed access tokens. But you need to pick the right authorization server and audience before tokens will validate. The abstract Flux contract is in Configuring OIDC; this page covers the Okta-specific steps.

What to register at Okta

You need an authorization server and an application:

  1. Authorization server. Okta provisions a default Custom Authorization Server in every Okta org. Its URL is https://<your-domain>.okta.com/oauth2/default and its default audience is api://default. For production, create a dedicated authorization server per environment (flux-prod, flux-staging) so issuer URLs and audiences are not shared across deployments.
  2. Application. Use API Services (the OIDC client_credentials variant) for server-to-server flows: workers, CI jobs, anything that gets a token via the client-credentials grant. Use Web Application for browser flows. Either way, grant the app access to your authorization server.

The audience field in Flux must match the authorization server’s audience exactly (api://default by default, or whatever you set when creating a custom server). The issuer field is the authorization server URL (no trailing slash).

Confirm the signing algorithm on the authorization server is RS256 — that is the default. Okta supports ES256 too; Flux accepts both.

Vendor-specific gotchas

The minimal Flux config

[flux.security.auth.oidc]
enabled  = true
issuer   = "https://your-domain.okta.com/oauth2/default"
audience = "api://default"
default_user_roles = ["viewer"]

Substitute your Okta domain and, if you created a custom authorization server, its ID and audience. The default_user_roles = ["viewer"] line opts into auto-provisioning on first sign-in; without it, unknown subjects get a Principal not provisioned 401. Set it to [] (or omit it) if you prefer to register every principal up-front via flux principals create.

jwks_cache_ttl = 3600 and clock_skew = 30 are the defaults and rarely need changing.

Verification

Pull the discovery document for your authorization server:

curl -s https://your-domain.okta.com/oauth2/default/.well-known/openid-configuration | jq .

Confirm:

Smoke-test a client-credentials token (API Services app):

curl -s --request POST https://your-domain.okta.com/oauth2/default/v1/token \
  --header 'Accept: application/json' \
  --header 'Authorization: Basic <base64(client_id:client_secret)>' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data 'grant_type=client_credentials&scope=flux.read' \
  | jq -r .access_token

Decode the payload and check iss, aud, exp, sub are all present. Hit Flux with it:

curl -H "Authorization: Bearer $TOKEN" https://flux.example.com/workflows

Look in the Flux server logs for Auto-provisioned principal <sub> on first sign-in, or OIDC token validation failed: Invalid audience if the authorization server’s audience does not match your config.

See Configuring OIDC for the four required claims, the deprecation of roles_claim, and the Flux principal-resolution flow.


Derived against Okta docs 2026-05.