Authentication: OIDC and local login
f5240f5Report a problem ↗cerbix authenticates people with any OpenID Connect provider, with built-in local passwords, or with both. Authorization always happens inside cerbix, through its own roles. This page covers both sign-in methods, the role model and the credentials that pipelines use.
Sign-in methods
Section titled “Sign-in methods”| Method | Enable with | Best for |
|---|---|---|
| OIDC | oidc.issuer, oidc.client_id, oidc.redirect_url |
Teams with an identity provider (Keycloak, Auth0, Okta, Google, Entra ID) |
| Local login | local.enabled: true |
Bootstrap, isolated installs, a break-glass account next to SSO |
Both methods need database.dsn: users and sessions live in PostgreSQL. Both issue the same server-side session: an opaque HttpOnly, SameSite=Lax cookie (cerbix_session by default) whose hash is stored in the database. session.ttl defaults to 24h; a saved login policy can override it. Set session.secure: false only for plain-HTTP development.
The login page asks GET /auth/config which methods are active and renders the OIDC button with its label.
OIDC in cerbix is authentication only. The flow is Authorization Code with PKCE (S256) and a nonce. cerbix verifies the ID token against the issuer’s discovery document, then reads the email, email_verified, name and preferred_username claims. Group or role claims are not read; access comes from cerbix memberships.
The first login provisions the user, keyed on the issuer and the sub claim (stored as oidc_sub). A changed email or display name updates the same user. A new user has no memberships and sees nothing until an organization admin adds them.
| Key | Default | Meaning |
|---|---|---|
oidc.issuer |
empty (OIDC off) | Issuer URL used for discovery |
oidc.client_id, oidc.client_secret |
— | Client credentials registered at the provider |
oidc.redirect_url |
— | https://<host>/auth/callback |
oidc.scopes |
["openid", "email", "profile"] |
Requested scopes |
oidc.button_label |
Continue with SSO |
Text of the login button |
oidc.post_logout_redirect_url |
empty | Where /auth/logout sends the browser |
oidc.bootstrap_admin_emails |
[] |
Emails promoted to global admin on login, only when the provider marks the email verified |
The YAML is a bootstrap seed. A global admin can change the provider at runtime under Settings → Administration → Authentication (PUT /api/v1/settings/oidc). After the first save, the database settings override the YAML.
Discovery never blocks startup. If the provider is unreachable, cerbix starts, logs oidc_build_failed, and retries every 30 s. Until it succeeds, /auth/login answers 503 and local login keeps working.
Example: Keycloak
Section titled “Example: Keycloak”In the realm you use for cerbix, create a client:
- Client type: OpenID Connect, Client ID:
cerbix. - Client authentication: on (a confidential client with a secret).
- Standard flow: on. Implicit flow: off. Service accounts roles: on only if pipelines will use client-credentials tokens.
- Valid redirect URIs:
https://cerbix.example.com/auth/callback. - Valid post logout redirect URIs:
https://cerbix.example.com/*. - Keep
emailandprofileas default client scopes so the ID token carries the email and name claims.
Then point cerbix at the realm:
oidc: issuer: "https://sso.example.com/realms/cerbix" client_id: "cerbix" client_secret: "${CERBIX_OIDC_CLIENT_SECRET}" redirect_url: "https://cerbix.example.com/auth/callback" button_label: "Continue with Keycloak" post_logout_redirect_url: "https://cerbix.example.com/" bootstrap_admin_emails: ["admin@example.com"]The issuer must be the URL Keycloak puts in the token’s iss claim. If cerbix reaches Keycloak through an internal hostname, configure Keycloak’s public hostname so both agree.
Local login
Section titled “Local login”With local.enabled: true, users sign in with an email and password at POST /auth/local/login. Passwords are hashed with argon2id; only the hash is stored. A wrong password and an unknown email return the same 401, and both run the same argon2id check, so response time does not reveal which accounts exist.
| Key | Default | Meaning |
|---|---|---|
local.min_password_length |
8 |
Minimum password length |
local.login_rate_limit_per_minute |
10 |
Attempts per client IP per minute; 0 disables. Above it: 429 |
security.admin_email, security.admin_password |
empty | On an empty database, creates a global admin at startup |
The bootstrap password is never generated or logged; without it no admin is created. Behind a reverse proxy, set server.trusted_proxy_count or server.trusted_proxy_cidrs so the rate limiter sees the real client IP.
Two-factor authentication
Section titled “Two-factor authentication”Local accounts can enroll a TOTP authenticator (RFC 6238: 6 digits, 30 s period) under Settings → Account → Security. Enabling it shows 8 single-use recovery codes once. After a correct password, the login then needs a current code or an unused recovery code; without one it returns 401 with "totp_required": true.
A global admin can require TOTP with the login policy (Settings → Administration → Authentication): none, admins or all. The policy applies to local sign-ins only. SSO users get multi-factor from their identity provider. The same policy can restrict sign-in to listed email domains; for OIDC this requires a verified email claim.
Password reset
Section titled “Password reset”Self-service reset works when local login is on and SMTP is configured (mail.smtp_host, mail.from, mail.public_base_url). POST /auth/local/reset/request always answers 200, so it reveals nothing about accounts. The emailed link is valid for one hour and works once.
Roles and permissions
Section titled “Roles and permissions”Access is a membership: a user, a role and a scope (an organization or one project). An organization membership applies to every project in it.
| Role | Scope | Grants |
|---|---|---|
| Global admin | Instance | Everything, plus organizations, users, instance settings, agent tokens and file-provider diagnostics |
org_admin |
Organization | Manage the organization: projects, members, API tokens, webhooks; full project access |
project_admin |
Project | Editor rights plus release-gate overrides |
editor |
Organization or project | Create and change monitors, services, channels, gate policies; record changes |
viewer |
Organization or project | Read access and gate evaluation |
A resource outside your memberships answers 404, so its existence stays hidden. A visible resource you may not change answers 403.
Organization admins manage members under Settings → Organization → Members. A user must sign in once before they can be added.
Machine access
Section titled “Machine access”API tokens
Section titled “API tokens”An organization admin creates a token under Settings → Organization → API tokens or with POST /api/v1/organizations/{orgID}/tokens (name, role, optional project_id, optional actions). The secret starts with cbx_ and is shown once. Send it as Authorization: Bearer <token>.
actions narrows the role to an allow-list. A deploy pipeline needs only this:
{ "name": "ci-checkout", "role": "editor", "project_id": "<project-id>", "actions": ["gate:evaluate", "change:record"] }The list is fixed at creation; create a new token to change it. Revoke a token with DELETE /api/v1/tokens/{tokenID}.
OIDC client-credentials tokens
Section titled “OIDC client-credentials tokens”While OIDC is active, cerbix also accepts a bearer JWT issued by the same provider, for example a Keycloak service account. The signature and issuer are verified; the audience is not checked. The service account becomes a user keyed on its sub and gets exactly the memberships you grant it.
Agent tokens for HTTP-pull probers are a separate credential; see Geo-distributed probers.