OIDC Configuration
Symphony uses OpenID Connect (OIDC) for all user authentication. If you are using the bundled Keycloak (available in the Docker Compose and Kubernetes installations), OIDC is pre-configured and you can skip this guide.
This page explains what Symphony requires from an external OIDC provider and how to configure specific providers. You will enter your OIDC issuer URL and client IDs in the setup wizard when Symphony starts for the first time. The wizard includes a Validate Configuration button that checks your settings against the provider before you submit—use it to catch errors early.
You do not need to set OIDC environment variables or Helm values in advance. The setup wizard provides all the fields you need, and its built-in validation gives immediate feedback on configuration errors. Environment variables and Helm values exist primarily for automated or scripted deployments.
Requirements
Symphony requires the following from any OIDC provider:
- OIDC Discovery—the provider must serve a
/.well-known/openid-configurationdocument at its issuer URL - Authorization Code flow with PKCE—both the UI and the CLI use the authorization code grant with Proof Key for Code Exchange (S256 challenge method)
- RS256 token signing—JSON Web Tokens must be signed with RS256
- Scopes—the provider must support:
openid,profile,email, andoffline_access - Localhost redirect URIs—the API client must allow
http://localhostredirect URIs for CLI login (see the API client row in Client Registrations)
Client Registrations
Symphony requires two client registrations in your OIDC provider:
| Client | Environment Variable | Type | Grant Type | Purpose |
|---|---|---|---|---|
| UI client | OIDC_UICLIENTID | Public (SPA) | Authorization Code + PKCE | Browser-based single-page application |
| API client | OIDC_CLIENTID | Public | Authorization Code + PKCE / Token validation | CLI login (cirata login) and backend API |
UI Client Settings
- Client type: Public (no client secret)
- Grant type: Authorization Code
- PKCE: Required, S256 challenge method
- Redirect URIs:
https://<hostname>—main login callback (no trailing slash)https://<hostname>/silent-renew.html—silent token renewal
- Post-logout redirect URI:
https://<hostname>(no trailing slash) - Trusted origin / Web origin:
https://<hostname> - Scopes:
openid profile email offline_access
Register these URIs exactly as shown. Some providers (notably Okta)
match redirect URIs byte-for-byte—a trailing slash or missing path causes
sign-in to fail with a redirect_uri error even though validation passed.
The UI sends the browser's origin (https://<hostname>, no trailing
slash), not https://<hostname>/.
API Client Settings (CLI Login)
The cirata login command authenticates by opening the user's browser to
the OIDC provider, then receiving the authorization code on a temporary
local HTTP server. This requires the API client to be configured as follows:
- Client type: Public (the CLI cannot securely store a client secret)
- Grant type: Authorization Code with PKCE (S256)
- Redirect URIs:
http://localhost:*orhttp://localhostwith wildcard port support. The CLI starts a temporary server on a random port (e.g.http://localhost:50437/callback) to receive the callback. Your OIDC provider must allow localhost redirect URIs for this client. - No client secret needed (public PKCE client)
If http://localhost is not configured as an allowed redirect URI for the
API client, cirata login will fail. The OIDC provider will show an
"Invalid redirect_uri" error in the browser, and the CLI will time out
waiting for a callback. See the provider-specific guides below for the
exact setting in each provider.
As a workaround, users can create an API key manually in the Symphony UI and log in with:
cirata login --address <hostname> --token <paste-token>
After authentication, the CLI uses the OIDC access token to create a
Symphony API key (POST /api/v1/keys). Subsequent CLI commands use
that API key, not the OIDC token. The API client does not need additional
server-side configuration beyond what is listed in this section.
Client Secrets
Some OIDC providers require a client secret for confidential clients.
Symphony supports optional client secrets for both the API client
(OIDC_CLIENTSECRET) and the UI client (OIDC_UICLIENTSECRET).
Client secrets are required when:
- Your provider requires client authentication for any token endpoint interaction
Client secrets are not needed when:
- The UI client is a public (SPA) client—most providers do not issue secrets for public clients
- The API client is a public (PKCE) client—used by the CLI for browser-based login
- Your provider is Keycloak with a public client configuration
When a client secret is provided, the setup wizard validates it against the identity provider during the Validate Configuration step. Client secrets are stored in the Symphony configuration file and are never exposed through the API.
Audience
The UI sends audience=https://<hostname>/api/v1 as a query parameter during
authorization. Symphony accepts tokens with any of these aud values:
https://<hostname>/api/v1—the explicit API audience- The API client ID (
OIDC_CLIENTID) - The UI client ID (
OIDC_UICLIENTID) account—Keycloak default
Most providers require explicit audience configuration:
| Provider | Where to Configure |
|---|---|
| Keycloak | No action needed—Keycloak sets aud to the client ID by default |
| Auth0 | Create an API with identifier https://<hostname>/api/v1 |
| Okta | Set the Audience field on the authorization server to https://<hostname>/api/v1 |
| Entra ID | Set the Application ID URI under "Expose an API" to https://<hostname>/api/v1 |
| No custom audience—tokens use the client ID as the audience |
Issuer URL Format
The OIDC_ISSUER value must be the domain and path only, without the
https:// prefix. Symphony prepends https:// automatically.
# Correct
OIDC_ISSUER=auth.example.com/realms/symphony
# Incorrect — do not include the scheme
OIDC_ISSUER=https://auth.example.com/realms/symphony
Issuer URL Quick Reference
| Provider | OIDC_ISSUER Format | Example |
|---|---|---|
| Keycloak | <host>/realms/<realm> | auth.example.com/realms/symphony |
| Auth0 | <tenant>.auth0.com | mycompany.auth0.com |
| Okta | <org>.okta.com/oauth2/<auth-server> | mycompany.okta.com/oauth2/default |
| Microsoft Entra ID | login.microsoftonline.com/<tenant-id>/v2.0 | login.microsoftonline.com/abc123-def456/v2.0 |
| Google Workspace | accounts.google.com | accounts.google.com |
Provider-Specific Guides
Keycloak
Keycloak organises clients within realms. Create a realm (e.g.
symphony) and register both clients inside it.
Issuer: <keycloak-host>/realms/<realm-name>
1. Create the UI Client
- Go to Clients → Create client
- Set Client ID to your chosen name (e.g.
symphony-ui) - Set Client type to Public
- Enable Standard flow (authorization code)
- Under Settings:
- Valid redirect URIs:
https://<hostname>/* - Valid post logout redirect URIs:
https://<hostname>/* - Web origins:
https://<hostname>
- Valid redirect URIs:
- Under Advanced → Advanced Settings:
- Set Proof Key for Code Exchange Code Challenge Method to S256
2. Create the API Client
- Go to Clients → Create client
- Set Client ID to your chosen name (e.g.
symphony-api) - Set Client type to Public
- Enable Standard flow (authorization code)—the CLI uses this for browser-based PKCE login
- Under Settings, add Valid redirect URIs:
http://localhost:*(for CLI login) - Under Advanced → Advanced Settings, set Proof Key for Code Exchange Code Challenge Method to S256
3. Configure Group Claims
To use Symphony's role-based access control, configure group or role claims in the token. See RBAC Configuration for detailed instructions.
Auth0
Auth0 uses Applications for client registrations and APIs for audience configuration.
Issuer: <tenant>.auth0.com/ (note the trailing slash—Auth0 requires it)
1. Create the UI Application
- Go to Applications → Create Application
- Choose Single Page Application
- Set Name to your chosen name (e.g.
Symphony UI) - Under Settings:
- Allowed Callback URLs:
https://<hostname>,https://<hostname>/silent-renew.html - Allowed Logout URLs:
https://<hostname> - Allowed Web Origins:
https://<hostname>
- Allowed Callback URLs:
- Note the Client ID—this is your
OIDC_UICLIENTID
2. Create the API
- Go to APIs → Create API
- Set Identifier (Audience) to
https://<hostname>/api/v1 - Set Signing Algorithm to RS256
- Note the Identifier—this is the audience value
3. Create the API Application
- Go to Applications → Create Application
- Choose Single Page Application or Native (both support PKCE natively)
- Set Name (e.g.
Symphony API) - Under Settings:
- Allowed Callback URLs:
http://localhost:*,https://<hostname>/oauth/login(localhost is used for CLI login)
- Allowed Callback URLs:
- Authorise it for the API you created in step 2
- Note the Client ID—this is your
OIDC_CLIENTID
Auth0 Notes
- Auth0 namespaces custom claims. If you configure group claims for RBAC,
they will appear as
https://your-namespace/groupsin the token. See RBAC Configuration for how to configure the groups claim name in Symphony. - The trailing slash in the issuer URL is required. Auth0 includes it in the
issclaim, and Symphony must match it exactly.
Okta
Okta uses Applications for client registrations and Authorization Servers for audience and scope configuration.
Issuer: <org>.okta.com/oauth2/<authorization-server-id>
Use the default authorization server or create a custom one.
1. Create the UI Application
- Go to Applications → Create App Integration
- Choose OIDC—OpenID Connect, then Single-Page Application
- Set App integration name (e.g.
Symphony UI) - Under Sign-in redirect URIs:
https://<hostname>(no trailing slash)https://<hostname>/silent-renew.html
- Under Sign-out redirect URIs:
https://<hostname>(no trailing slash) - Under Trusted Origins: add
https://<hostname> - Note the Client ID—this is your
OIDC_UICLIENTID
2. Create the API Application
- Go to Applications → Create App Integration
- Choose OIDC—OpenID Connect, then Native Application (supports PKCE with localhost redirect)
- Set App integration name (e.g.
Symphony API) - Under Sign-in redirect URIs:
http://localhost:*,https://<hostname>/oauth/login(localhost is used for CLI login) - Note the Client ID—this is your
OIDC_CLIENTID
3. Configure the Authorization Server
- Go to Security → API → Authorization Servers
- Select your authorization server (e.g.
default) or create a custom one - Under Settings, set the Audience to
https://<hostname>/api/v1 - Under Scopes, verify that
openid,profile,email, andoffline_accessare available - Under Access Policies, ensure a policy and rule allow the Authorization Code grant type for the scopes above
4. Assign Users to the Applications
- Open each application (UI and API) in Applications
- Go to the Assignments tab
- Click Assign and add the users or groups that should have access
If users are not assigned to the application, Okta will return a 400 "User is not assigned to the client application" error after login. You can assign the Everyone group for broad access.
Okta Notes
- You must use a custom authorization server (e.g.
default), not the org authorization server. The org authorization server (<org>.okta.comwithout/oauth2/...) issues opaque access tokens that Symphony cannot validate. The issuer URL must be<org>.okta.com/oauth2/default(or your custom server name). - Okta matches redirect URIs byte-for-byte. Unlike Auth0 or Entra ID,
Okta does not normalize trailing slashes or paths. Register
https://<hostname>(no trailing slash) for sign-in and sign-out, nothttps://<hostname>/—otherwise sign-in fails with aredirect_urierror even though validation passes. Usehttp://localhost:*for the Native Application so any ephemeral port chosen bycirata loginis accepted. - The Audience field on the authorization server must match
https://<hostname>/api/v1. Without this, Okta issues tokens with a different audience and Symphony will reject them with a 401 error. - Ensure the authorization server's Access Policies include a rule that allows the Authorization Code grant type. Without this, Okta returns a "Policy evaluation failed" error after login.
Microsoft Entra ID (Azure AD)
Entra ID uses App registrations for client configuration.
Issuer: login.microsoftonline.com/<tenant-id>/v2.0
1. Create the App Registration
- Go to Microsoft Entra ID → App registrations → New registration
- Set Name (e.g.
Symphony) - Under Supported account types, choose your tenant model
- Click Register
2. Configure the UI Platform
- Go to Authentication → Add a platform → Single-page application
- Set Redirect URIs:
https://<hostname>(no trailing slash)https://<hostname>/silent-renew.html
- Check Access tokens and ID tokens under Implicit grant
- Note the Application (client) ID—this is your
OIDC_UICLIENTID
3. Configure the API Audience
- Go to Expose an API on the app registration
- Set Application ID URI to
https://<hostname>/api/v1—this becomes theaudclaim in access tokens and must match what Symphony expects - Add a scope (e.g.
access_as_user)
4. Create a Second App Registration for the API Client
- Create another app registration (e.g.
Symphony API) - Under Authentication → Add a platform, choose Mobile and desktop applications (supports PKCE with localhost redirect)
- Add Redirect URI:
http://localhost(Entra ID handles port wildcards differently—http://localhostmatches any port) - Note the Application (client) ID—this is your
OIDC_CLIENTID - Under API permissions, add the scope from step 3
Entra ID Notes
- The tenant ID is found on the Overview page of your Entra ID tenant.
- Entra ID v2.0 tokens use the
ver: "2.0"claim. Ensure you use the/v2.0issuer endpoint. - The Application ID URI set in "Expose an API" becomes the
audclaim in access tokens. It must be set tohttps://<hostname>/api/v1or Symphony will reject tokens with an audience mismatch error. - For group claims, configure Token configuration → Add groups claim in the app registration. See RBAC Configuration for details.
Google Workspace
Issuer: accounts.google.com
Google can be used for authentication, but it does not natively support group claims in OIDC tokens. This means RBAC group mappings will not work out of the box.
1. Create OAuth Credentials
- Go to the Google Cloud Console
- Navigate to APIs & Services → Credentials → Create Credentials → OAuth client ID
- Choose Web application
- Set Authorized redirect URIs:
https://<hostname>(no trailing slash)https://<hostname>/silent-renew.htmlhttps://<hostname>/oauth/loginhttp://localhost:*(for CLI PKCE login)
- Note the Client ID values
Google Notes
- Google does not support custom audience values. Tokens will contain Google's own client ID as the audience.
- Google does not include group claims in tokens. For RBAC, you will need to use individual user role assignments instead of group mappings. See RBAC Configuration for workarounds.
- The
offline_accessscope is not supported by Google. Useaccess_type=offlineas a parameter instead, though silent renewal may behave differently.
Troubleshooting
Using the Setup Wizard Validation
The setup wizard includes a Validate Configuration button that checks your DNS hostname and OIDC settings before you submit. Click the button after filling in all OIDC fields. The validation contacts the provider's discovery endpoint and token endpoint to verify that the discovery document is reachable, required endpoints are present, signing algorithms and scopes are supported, client IDs are recognized, and (when provided) client secrets are valid.
Each check reports pass, info, warning, or fail, along with a description of the issue and instructions for resolving it. Errors should be fixed before proceeding. Warnings should be investigated but do not block setup. After editing any field the result is cleared and you should re-validate.
Additional features:
- Copy diagnostics: A clipboard icon appears after validation. Click it to copy all check results (including passes) for sharing with support.
- Disable TLS Verification: A switch next to the OIDC Issuer field
disables TLS certificate verification for providers with self-signed or
private CA certificates. This setting is saved to the configuration.
For production, use
OIDC_CA_CERTinstead. - Comprehensive logging: All validation checks are logged to the container logs during initial setup, including full diagnostic detail and resolution guidance.
For a detailed description of every check, what causes it to fail, and step-by-step resolution instructions, see Setup Wizard Validation.
Issuer URL Format Errors
The most common mistake is including https:// in the OIDC_ISSUER value.
Symphony adds the scheme automatically:
# Wrong
OIDC_ISSUER=https://auth.example.com/realms/symphony
# Right
OIDC_ISSUER=auth.example.com/realms/symphony
Trailing slashes on OIDC_ISSUER are normalized automatically—you do not
need to worry about whether to include one. This normalization applies
only to the issuer URL; redirect URIs are not normalized and must
match what the provider has registered character-for-character (see
Redirect URI Mismatch).
Discovery Endpoint Not Reachable
Verify that Symphony can reach the OIDC discovery endpoint:
curl -s https://<OIDC_ISSUER>/.well-known/openid-configuration | jq .
If the provider uses a different internal URL (e.g. in Docker or Kubernetes
networks), set OIDC_INTERNAL_BASE_URL to the URL reachable from the
Symphony server.
Redirect URI Mismatch
OIDC providers strictly validate redirect URIs. Unlike the OIDC_ISSUER
value, redirect URIs are not normalized—trailing slashes and paths
must match exactly on providers like Okta. Ensure the URIs registered in
your provider match what Symphony uses character-for-character:
UI client (SPA):
- Sign-in:
https://<EXTERNAL_HOSTNAME>(no trailing slash) - Silent renewal:
https://<EXTERNAL_HOSTNAME>/silent-renew.html - Post-logout:
https://<EXTERNAL_HOSTNAME>(no trailing slash) - Trusted origin / Web origin:
https://<EXTERNAL_HOSTNAME>
API client (backend + CLI):
- Web sign-in:
https://<EXTERNAL_HOSTNAME>/oauth/login - CLI PKCE callback:
http://localhost:<port>/callback—cirata loginlistens on 127.0.0.1 on an ephemeral port chosen by the OS, so the port varies per login attempt. Registerhttp://localhost:*(Okta, Auth0),http://localhost(Entra ID—matches any port), or the equivalent wildcard for your provider. Where the provider does not allow wildcard loopback redirects, users can authenticate with an API key instead (cirata login --token <api-key>).
The setup wizard's Validate Configuration button lists these URIs
for your current EXTERNAL_HOSTNAME in the "Additional items to verify"
advisory after validation succeeds—copy them directly into your provider.
Common issues:
- Trailing slash on
https://<EXTERNAL_HOSTNAME>that does not match the browser origin (the UI sendswindow.location.origin, no slash) - Registering
http://localhostwithout the port wildcard on providers that require explicit port matching - Using
http://instead ofhttps://for the public hostname - Hostname mismatch between
EXTERNAL_HOSTNAMEand the registered URI
Audience Mismatch / 401 After Login
If you see 401 errors on /api/v1/usertoken after a successful login
redirect, the most likely cause is an audience mismatch—the access token's
aud claim does not match what Symphony expects. The accepted values
are:
https://<EXTERNAL_HOSTNAME>/api/v1- The
OIDC_CLIENTIDvalue - The
OIDC_UICLIENTIDvalue account
Another common cause is opaque (non-JWT) access tokens. Some providers issue opaque tokens when no API audience is registered, and Symphony cannot validate these.
Provider-specific fixes:
- Keycloak: the client ID is used as the audience by default—no additional configuration is needed.
- Auth0: create an API in Applications → APIs with identifier
https://<hostname>/api/v1. - Okta: set the Audience field on your custom authorization server
(Security → API → your server → Settings) to
https://<hostname>/api/v1. You must use a custom authorization server (e.g.default)—the org authorization server issues opaque tokens. - Entra ID: set the Application ID URI under "Expose an API" on
your app registration to
https://<hostname>/api/v1. - Google: Google does not support custom audiences. Symphony accepts the client ID as the audience.
CORS Issues
The browser must be able to reach the OIDC provider directly for the authorization code flow. If you see CORS errors in the browser console:
- Verify that
https://<EXTERNAL_HOSTNAME>is listed as an allowed origin (or "Web Origin" / "Trusted Origin") in your OIDC provider's client settings - Check that the provider's CORS configuration allows the
/.well-known/openid-configurationand token endpoints
Clock Skew
Symphony allows up to 1 minute of clock skew when validating token timestamps. If you see token expiration errors, verify that the clocks on your Symphony server and OIDC provider are synchronised (e.g. using NTP).
Keycloak Login Error Events During Validation
When running the setup wizard validation with Keycloak, you may see
CLIENT_LOGIN_ERROR events in Keycloak's event log:
type="CLIENT_LOGIN_ERROR", clientId="symphony-api", error="invalid_client_credentials"
type="CLIENT_LOGIN_ERROR", clientId="symphony-ui", error="invalid_client",
reason="Public client not allowed to retrieve service account"
These are expected and harmless. The validation probe sends a
client_credentials grant to verify that client IDs are recognized by
the provider. Keycloak logs a warning for each probe because:
- Confidential clients (like
symphony-api) receive a probe without the correct secret, triggeringinvalid_client_credentials. - Public clients (like
symphony-ui) cannot use theclient_credentialsgrant type at all, triggeringinvalid_client.
These events do not indicate a misconfiguration. They only appear during validation and do not recur during normal operation.
See Also
- Setup Wizard Validation—Detailed descriptions of each setup wizard check with resolution steps
- RBAC Configuration—Configuring group claim mappings for role-based access control
- Configuration Reference—Complete field reference including OIDC settings
- TLS and Certificates—TLS configuration for securing connections to your OIDC provider