Skip to main content

Authentication

Atlas delegates authentication to Keycloak using OpenID Connect. Each tenant has its own Keycloak realm; a request carries a JWT from which the backend derives the tenant, user, and roles. Authorization is role-based, and the tenant claim drives the database Row-Level Security that isolates data.

Token flow

The frontend uses keycloak-js with PKCE and refreshes tokens ahead of expiry. In development the Vite proxy keeps /realms and /resources same-origin; in production nginx does the same so cookies and redirects behave.

What the backend does with a token

PlatformAuthMiddleware (src/api/auth.py) and KeycloakClient (src/integrations/keycloak_client.py) together:

  1. Extract the Bearer token.
  2. Validate it against the tenant's Keycloak realm.
  3. Read tenant_id, sub (user id), and roles.
  4. Build an AuthContext on request.state and bind the tenant to the DB session for RLS.

A request without a valid token, or without a resolvable tenant, is rejected — require_tenant returns 401. This is the fail-closed default described in Security & multi-tenancy.

Roles

RoleCapability
adminFull access including Settings and Studio configuration
analystRun and review investigations, resolve conflicts
viewerRead-only access
workflow_editorAuthor and run low-code workflows

Endpoint guards enforce these; Studio and Settings are admin-only. Workflow-specific authorization lives in src/workflows/auth.py. Role assignment is managed via auth_router (admin).

Tenant resolution (frontend)

Before login, the Console resolves which realm to use from the URL slug:

See Frontend architecture for the provider tree that implements this.

Service-to-service & workers

Temporal workers operate within a tenant context propagated from the originating request, so activities persist data under the correct tenant and RLS applies to worker database access just as it does to the API.