Authentication modes
Observal supports password auth, API keys, OAuth / OIDC, and SAML. The public login page shows only the methods enabled for the deployment.
Use
deployment.sso_only=true when password login should be hidden and only SSO should be available.
SSO-only mode
deployment.sso_only controls whether password-based authentication is available.
Set it in Admin → SSO → Access policy. Confirm OIDC or SAML works with a real test user before enabling it.
Self registration
Controls whether visitors can create their own Observal account from the login page.
You can set this in the web UI at Admin → Settings → Authentication → Self Registration Enabled. If you prefer the CLI, set the same dynamic setting directly:
user role. They cannot review submissions, manage users, or change server settings unless an admin promotes them later.
Disable it again with:
The bootstrap flow
On a fresh server with no users, the/api/v1/auth/bootstrap endpoint is available to localhost only. When you run observal auth login, the CLI detects the empty user table and bootstraps an admin account interactively.
This is how you create the first admin without any pre-existing credential.
Once the first admin exists, bootstrap is disabled.
JWT signing keys
Tokens are signed with asymmetric keys (ES256 by default, RS256 also supported). Keys are generated on first startup and stored in theapidata volume at $JWT_KEY_DIR (default /data/keys).
Critical: back up $JWT_KEY_DIR
Losing these keys invalidates every access and refresh token. All users must log in again. Tokens rotate, but only the private key can issue new ones, and there is no recovery path without the keys.
Back up the apidata volume every time you back up Postgres. See Backup and restore.
Key rotation and algorithm changes
For a same-algorithm emergency rotation, stop the API, back up and removesigning.pem, then restart. New keys are generated and existing sessions must authenticate again.
To move between ES256 and RS256, change JWT_SIGNING_ALGORITHM and restart. Observal archives the old public key, generates the selected key type, publishes both in JWKS, and continues verifying old tokens until they expire. New tokens use only the configured algorithm. Unsupported algorithms and token headers that do not match the resolved key type are rejected.
If the signing key is encrypted, use JWT_KEY_PASSWORD_FILE and rotate the password and key together during a planned restart.
File-backed SAML keys
SAML service-provider keys can remain outside the settings database:NAME_FILE form. File-backed values stay in memory rather than being copied into PostgreSQL or Redis. See Configuration.
OAuth / OIDC SSO
Set these three in Admin → SSO → SSO settings, then restart the API so the OIDC client is rebuilt:
Observal uses Authlib and reads the IdP discovery document, so any OIDC-compliant provider works (Auth0, Okta, Azure AD, Google Workspace, Keycloak, Authentik, Dex, etc.).
OIDC Client ID
The public client identifier from your IdP application registration.OIDC Client Secret
The private client secret from your IdP application registration. It is stored encrypted and is never shown again after saving.OIDC Discovery URL
The.well-known/openid-configuration URL for your IdP tenant or authorization server.
Redirect URI
Configure your IdP to allow:FRONTEND_URL=https://observal.your-company.internal, that’s:
First OAuth login
The first user who logs in via OAuth is not automatically an admin. Bootstrap a local admin first (viaobserval auth login before enabling OAuth, or via the demo super admin), then use that admin to promote the OAuth user.
Scope / claims
Observal requests standardopenid profile email scope. The IdP’s email claim is the canonical user identifier.
Google OAuth (first-class provider)
Google sign-in runs as its own provider, separate from the generic OIDC slot above. Both can be enabled at the same time, so a deployment can offer Okta and Google on the login screen. Set these in the SSO settings page, or set them as container env vars for one-time import at startup. The Sign in with Google button appears after the API restarts:Creating the Google OAuth client
- Open the Google Cloud Console in the project you want to use.
- Click Create Credentials → OAuth client ID.
- Application type: Web application.
- Authorized JavaScript origins:
{FRONTEND_URL}(e.g.https://observal.your-company.internal). - Authorized redirect URI:
{FRONTEND_URL}/api/v1/auth/oauth/google/callback. - Copy the generated Client ID and Client secret into SSO settings or your container env.
- Restart the API container so the Authlib client is rebuilt.
Restricting to specific email domains
SetGOOGLE_OAUTH_ALLOWED_DOMAINS to a comma-separated list of domains. Anyone outside the list is rejected with a 403, even if they have a valid Google account.
@gmail.com addresses) to provision themselves as role=user.
Notes
- Observal additionally requires Google’s
email_verifiedclaim to betrue. Unverified accounts (rare on Google but possible) are rejected with a 400. - The first Google user is not automatically an admin (matches the generic OIDC behavior). Bootstrap a local admin first, then use that account to promote the Google user.
- The auth provider and Google subject ID are recorded on the user row (
auth_provider="google",sso_subject_id=<google-sub>) for audit purposes.
GitHub OAuth (first-class provider)
GitHub sign-in runs as its own provider, alongside generic OIDC and Google. Unlike those two, GitHub is plain OAuth 2.0 (not OIDC): there is no discovery URL and no ID token. Observal fetches the profile and email list from the GitHub REST API after the code exchange. Set these in the SSO settings page, or as container env vars for one-time import at startup. The Sign in with GitHub button appears after the API restarts:Creating the GitHub OAuth app
- Open Settings → Developer settings → OAuth Apps (on your personal account or, preferably, your GitHub organization) and click New OAuth App.
- Homepage URL:
{FRONTEND_URL}(e.g.https://observal.your-company.internal). - Authorization callback URL:
{FRONTEND_URL}/api/v1/auth/oauth/github/callback. - Copy the generated Client ID and generate a Client secret; put both into SSO settings or your container env.
- Restart the API container so the Authlib client is rebuilt.
Restricting to GitHub organizations
SetGITHUB_OAUTH_ALLOWED_ORGS to a comma-separated list of GitHub organization slugs. Only active members of at least one listed org can sign in; everyone else is rejected with a 403. Pending invitations don’t count.
read:org scope (in addition to read:user user:email) so it can see private org memberships. Members may need to grant/request org approval for the OAuth app if the org restricts third-party access.
Leave it unset to allow any GitHub account to provision itself as role=user.
Notes
- Observal only accepts verified email addresses from
GET /user/emails(preferring the primary). The profile-levelemailfield is never trusted, and accounts with no verified email are rejected with a 400. - Departments are not populated automatically from GitHub (there is no groups claim). Assign them in Admin → Users, individually or via bulk upload — same as Google users.
- The auth provider and the numeric GitHub user ID are recorded on the user row (
auth_provider="github",sso_subject_id=<github-id>). The numeric ID is used instead of the login handle because handles can be renamed and re-registered.
Role-based access control (RBAC)
Four built-in roles enforced on every endpoint:
Change a user’s role:
/settings/users.
API keys
Users can generate API keys for scripts and CI. The key inherits the user’s role.POST /api/v1/auth/token/revoke.
Rate limits
Auth endpoints are rate-limited to slow brute-force attempts:
Tighten for public-facing deployments.
Password reset
There is no self-service reset flow. The login page says Forgot password? Contact your admin. — an admin resets the account from Admin > Users in the web UI or with the CLI:--generate has the server mint a random password and the CLI prints it once. Hand it to the user out-of-band (Slack, phone); they must change it at their next sign-in.
Operational controls
Observal includes:- Audit logging: every privileged action lands in ClickHouse’s
audit_log - SSO-only mode (
deployment.sso_only=true)
docs/self-hosting/sso-cli.md for SSO CLI commands.

