> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solya.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication & multi-tenancy

> How login, sessions, organization scoping, and org switching work.

This page covers the platform's identity and tenancy model. For calling the API as an
external program, see [Authentication](/en/developers/authentication).

Here's how login and organization scoping work:

```mermaid theme={null}
sequenceDiagram
    participant User
    participant Browser
    participant Keycloak
    participant NextAuth
    participant App
    
    User->>Browser: Visit Solya
    Browser->>Keycloak: Initiate OpenID Connect login
    Keycloak->>Keycloak: Authenticate user
    Keycloak->>Browser: Return ID token with groups<br/>(tenant-*, ops-admins)
    Browser->>NextAuth: Exchange token for session
    NextAuth->>App: Resolve groups to organizations
    App->>App: Set active org (saved choice,<br/>default, or first available)
    App->>Browser: Session with organizationId,<br/>roles, permissions
    Browser->>App: Subsequent requests include session
    App->>App: All queries scoped to organizationId
```

## Login (Keycloak + NextAuth)

Users sign in through **Keycloak** (OpenID Connect); **NextAuth** manages the session.
At login, Solya reads the user's Keycloak **groups**:

* Groups follow the convention **`tenant-<org-name>`** (e.g. `tenant-adidas`). Each
  resolves to an internal **organization**.
* The special **`ops-admins`** group marks an operations administrator.

The resolved organizations are stored as the user's **available organizations**, and the
first becomes their **default**.

## The session

A session carries the active organization and the user's effective access in it:

* `organizationId` / `organizationName` — the **active** organization.
* `availableOrganizationIds` — every organization the user can access.
* `defaultOrganizationId` — the fallback organization.
* `roles` and `effectivePermissions` — the user's roles and the union of permissions
  (direct + team) **in the active organization**.
* `currency`, `language`, and an `isOpsAdmin` flag.

## Organization scoping (multi-tenancy)

Every entity is scoped by `organizationId`, and **the active organization is derived from
the authenticated session, never from client input**. Server actions and API routes
resolve the organization, then services run all queries against it — so a user or token
can only ever read or write their own organization's data.

## Switching organizations

A user who belongs to several organizations has an **active** one selected from (in order):
their saved choice, then their default, then the first available. Switching changes the
active organization for subsequent requests; roles and permissions are re-resolved for the
newly active org.

## Two ways in

| Caller              | Mechanism                                                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **Browser (human)** | NextAuth session cookie established via Keycloak                                                                            |
| **Program / agent** | `Authorization: Bearer solya_sa_…` service-account token (org-scoped) — see [Authentication](/en/developers/authentication) |

Both resolve to the same organization-scoped context, so the same endpoints serve both.
Server actions enforce auth (and optional permissions); API routes do the same and
additionally support an internal-bearer mode for internal services.
