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

# Authentication

> Deep dive into Keycloak authentication, OIDC flows, JWT token management, and machine-to-machine authentication on CRAFT.

# Authentication

CRAFT uses **Keycloak** for all authentication. Every API request requires a valid JWT token, and each organization maps to a dedicated Keycloak realm. This page covers OIDC flows, token management, machine-to-machine authentication, and session configuration.

## Authentication Architecture

<Tabs>
  <Tab title="User Authentication">
    Browser-based applications authenticate using the **OIDC Authorization Code flow with PKCE**:

    1. The frontend redirects the user to the Keycloak realm login page
    2. The user authenticates (password, SSO, or MFA)
    3. Keycloak returns an authorization code to the frontend callback URL
    4. The frontend exchanges the code for JWT tokens (access + refresh + ID)
    5. The access token is included in all API requests as `Authorization: Bearer <token>`

    The PKCE extension protects against authorization code interception attacks in public clients (browser-based applications that cannot securely store a client secret).
  </Tab>

  <Tab title="Machine-to-Machine">
    Service accounts, CI/CD pipelines, and automation tools authenticate using the **Keycloak client credentials grant**:

    ```bash theme={null}
    curl -X POST \
      "https://<keycloak-host>/realms/<org-id>/protocol/openid-connect/token" \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -d "grant_type=client_credentials" \
      -d "client_id=<service-account-id>" \
      -d "client_secret=<service-account-secret>"
    ```

    Client credentials are managed entirely by Keycloak -- there is no custom API key lifecycle. Keycloak handles credential rotation, revocation, and expiration.
  </Tab>
</Tabs>

## JWT Token Structure

Access tokens issued by Keycloak contain the following claims used by the platform:

| Claim    | Source             | Description                                                |
| -------- | ------------------ | ---------------------------------------------------------- |
| `sub`    | Keycloak           | Unique user identifier                                     |
| `iss`    | Keycloak realm URL | Issuer URL including the realm ID                          |
| `org_id` | Derived from realm | Organization ID (realm ID = org ID)                        |
| `groups` | Keycloak groups    | Group memberships for role mapping                         |
| `aud`    | Keycloak client    | Audience -- identifies the intended recipient of the token |
| `exp`    | Keycloak           | Token expiration timestamp                                 |
| `iat`    | Keycloak           | Token issuance timestamp                                   |

<Warning>
  The `project_id` is never stored in the JWT. It is passed via the `X-Project-ID` HTTP header or as a path parameter on each API request. This allows a single token to access multiple projects within the same organization.
</Warning>

## Token Validation

Platform services validate JWT tokens using the following process:

<Steps>
  <Step title="JWKS retrieval">
    The service fetches the Keycloak JWKS (JSON Web Key Set) from the realm's well-known endpoint: `https://<keycloak-host>/realms/<org-id>/protocol/openid-connect/certs`
  </Step>

  <Step title="Signature verification">
    The token's RS256 signature is verified against the public key from the JWKS endpoint.
  </Step>

  <Step title="Claims validation">
    The service validates the `iss` (issuer) and `exp` (expiration) claims. Expired or malformed tokens receive a `401 Unauthorized` response. Audience (`aud`) validation is not currently enforced; this is a known limitation tracked for remediation.
  </Step>

  <Step title="Organization extraction">
    The `org_id` is extracted from the realm portion of the issuer URL. All subsequent queries are scoped to this organization.
  </Step>
</Steps>

## Multi-Realm Architecture

Each organization in the platform is a separate Keycloak realm:

| Aspect                   | Implementation                                  |
| ------------------------ | ----------------------------------------------- |
| **Realm ID**             | Equals the organization ID                      |
| **User directory**       | Each realm has its own user store               |
| **IdP configuration**    | SSO providers are configured per realm          |
| **Client registrations** | Applications and service accounts are per realm |
| **Session management**   | Sessions are isolated per realm                 |

This architecture provides complete tenant isolation at the authentication level. A user authenticated in one realm cannot access resources in another realm's organization.

## Single Sign-On (SSO)

Keycloak supports SSO via both OIDC and SAML 2.0 for enterprise identity providers:

| IdP                | Protocol | Configuration                          |
| ------------------ | -------- | -------------------------------------- |
| Microsoft Entra ID | OIDC     | App registration + group claims        |
| Okta               | OIDC     | Application integration + group filter |
| Google Workspace   | OIDC     | OAuth client credentials               |
| PingFederate       | SAML 2.0 | SP metadata exchange                   |

### SSO Features

* **Per-tenant configuration**: Each organization connects to its own IdP
* **Just-in-time provisioning**: Users are created on first SSO login
* **Forced SSO**: Organizations can disable password login, requiring all users to authenticate via the configured IdP
* **Session management**: Configurable idle timeout, max session duration, and forced re-authentication

See the [SSO Integration guide](/guides/sso-integration) for step-by-step configuration.

## Anonymous Access

The platform supports optional anonymous read-only access for public resources:

| Setting            | Value                                                                                            |
| ------------------ | ------------------------------------------------------------------------------------------------ |
| **Scope**          | Read-only access to PUBLIC entities via search and list endpoints                                |
| **Rate limit**     | 30 requests per minute (target; must be enforced at ingress/WAF layer by deploying organization) |
| **Redaction**      | Security schemes and credentials are omitted from responses                                      |
| **Default**        | Disabled per tenant; must be explicitly enabled                                                  |
| **Implementation** | `OptionalAuth` dependency returns `None` for unauthenticated requests                            |

<Note>
  Anonymous endpoints must be explicitly allowlisted in the service configuration. The standard `get_auth()` dependency always requires a valid JWT.
</Note>

## Rate Limiting

Rate limiting must be enforced at the ingress/WAF layer by the deploying organization. The following targets are recommended:

| Operation Type                    | Recommended Limit | Enforcement        |
| --------------------------------- | ----------------- | ------------------ |
| Writes (POST, PUT, PATCH, DELETE) | 60/min            | Ingress/WAF policy |
| Reads (GET, POST :search)         | 300/min           | Ingress/WAF policy |
| Bulk operations                   | 10/min            | Ingress/WAF policy |
| Anonymous reads                   | 30/min            | Ingress/WAF policy |

When rate limiting is configured, the ingress layer should return `429 Too Many Requests` with a `Retry-After` header and include standard rate limit response headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`).

<Warning>
  Rate limiting is not enforced by default in the platform. Deploying organizations must configure rate limiting at their ingress controller or WAF (e.g., GCP Cloud Armor, AWS WAF, Nginx rate limiting).
</Warning>

## Token Management Best Practices

<AccordionGroup>
  <Accordion title="Token refresh strategy">
    Use the refresh token to obtain new access tokens before the access token expires. Keycloak refresh tokens have a longer lifetime than access tokens. Implement proactive refresh (e.g., refresh when 75% of the token lifetime has elapsed) rather than waiting for a 401 response.
  </Accordion>

  <Accordion title="Client credential rotation">
    Rotate client secrets periodically. Keycloak supports multiple active client secrets during rotation, allowing a grace period for credential updates across services.
  </Accordion>

  <Accordion title="Token storage">
    Never store tokens in localStorage for browser applications. Use httpOnly cookies or in-memory storage with the token refresh flow. For server-side applications, store tokens in encrypted session state.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="401 Unauthorized on valid token">
    Check the token's `iss` claim matches the expected Keycloak realm URL. Verify the Keycloak server is reachable and the JWKS endpoint returns valid keys. Clock skew between services can cause premature token expiration.
  </Accordion>

  <Accordion title="SSO redirect loop">
    Verify the redirect URI configured in the IdP matches the Keycloak broker endpoint. Check that the Keycloak realm has the identity provider enabled and the browser flow is configured correctly.
  </Accordion>

  <Accordion title="Groups claim missing from token">
    Ensure a group mapper is configured in the Keycloak client settings. The mapper must be set to add group memberships to the access token (not just the ID token).
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="SSO Integration" icon="key" href="/guides/sso-integration">
    Configure SSO with Entra ID, Okta, or Google Workspace.
  </Card>

  <Card title="RBAC Configuration" icon="user-shield" href="/guides/rbac-configuration">
    Set up OpenFGA roles and permissions for authorization.
  </Card>

  <Card title="API Authentication" icon="code" href="/api-reference/authentication">
    Learn how to authenticate API requests with JWT tokens.
  </Card>

  <Card title="Network Security" icon="shield" href="/security/network-security">
    Review TLS and network policies for securing authentication flows.
  </Card>
</CardGroup>
