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

# Authentication

> Learn how to authenticate with the Prisme.ai API

The Prisme.ai API uses a robust authentication system to secure access to resources. This guide explains how authentication works and how to implement it in your API requests.

## Authentication Methods

<Tabs>
  <Tab title="JWT Authentication">
    JSON Web Tokens (JWTs) are the primary authentication method for web clients and interactive sessions.

    <Steps>
      <Step title="Obtain a JWT">
        JWTs are issued in two scenarios:

        1. **OpenID Connect (OIDC) authentication**: After authenticating with the OIDC server (the api-gateway), clients receive an authorization code that can be exchanged for a JWT. Find your current JWT in the `access-token` cookie sent to the `https://api.studio.prisme.ai/v2/me` API after opening any Prisme.ai page
        2. **Anonymous authentication**: The `/v2/login/anonymous` endpoint initiates unauthenticated sessions and returns a JWT.

        ```bash theme={null}
        # Example of anonymous login
        curl -X POST "https://api.studio.prisme.ai/v2/login/anonymous" \
             -H "Content-Type: application/json"
        ```

        Response contains a JWT:

        ```json theme={null}
        {
          "userId": "anon-123456",
          "sessionId": "session-789012",
          "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0xIn0..."
        }
        ```
      </Step>

      <Step title="Use the JWT">
        Include the JWT in the Authorization header for API requests:

        ```bash theme={null}
        curl -X GET "https://api.studio.prisme.ai/v2/workspaces" \
             -H "Content-Type: application/json" \
             -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0xIn0..."
        ```
      </Step>
    </Steps>

    <Warning>
      JWTs have an expiration time defined by the `ACCESS_TOKENS_MAX_AGE` setting (default is 30 days). Your application should handle token refreshing or re-authentication when tokens expire.
    </Warning>
  </Tab>

  <Tab title="Access Tokens">
    Access tokens are opaque tokens generated for longer-term programmatic access. They are ideal for scripts, integrations, and backend applications.

    <Steps>
      <Step title="Generate an Access Token">
        Authenticated users can generate access tokens using the `/v2/user/accessTokens` endpoint:

        ```bash theme={null}
        curl -X POST "https://api.studio.prisme.ai/v2/user/accessTokens" \
             -H "Content-Type: application/json" \
             -H "Authorization: Bearer YOUR_JWT" \
             -d '{
                   "name": "My Integration Token",
                   "expiresAt": "2025-04-28T10:13:21.719Z"
                 }'
        ```

        The response includes the access token:

        ```json theme={null}
        {
          "name": "My Integration Token",
          "expiresAt": "2023-12-31T23:59:59Z",
          "userId": "user id",
          "token": "at:1234abcd5678efgh",
          "_id": "token id"
        }
        ```
      </Step>

      <Step title="Use the Access Token">
        Include the access token in the Authorization header the same way as JWTs:

        ```bash theme={null}
        curl -X GET "https://api.studio.prisme.ai/v2/workspaces" \
             -H "Content-Type: application/json" \
             -H "Authorization: Bearer at:1234abcd5678efgh"
        ```
      </Step>
    </Steps>

    <Warning>
      Access tokens cannot be recovered if lost. Store them securely and never expose them in client-side code.
    </Warning>
  </Tab>

  <Tab title="API Keys">
    API keys are scoped to specific workspaces and provide granular permission control for integrations.

    <Steps>
      <Step title="Create an API Key">
        Workspace administrators can create API keys with specific permissions:

        ```bash theme={null}
          curl --location 'https://api.studio.prisme.ai/v2/workspaces/<WORKSPACE_ID>/security/apikeys' \
          --header 'Authorization: Bearer <YOUR_JWT>' \
          --header 'Content-Type: application/json' \
          --data '{
              "name": "Your ApiKey name",
              "rules": [
                  {
                      "action": "read",
                      "subject": "workspaces"
                  },                
                  {
                      "action": "create",
                      "subject": "files"
                  }
              ]
          }'
        ```

        The response includes the API key:

        ```json theme={null}
          {
              "apiKey": "<apikey>",
              "name": "Your ApiKey name",
              "rules": [
                  {
                      "action": [
                          "read"
                      ],
                      "subject": "workspaces",
                      "conditions": {
                          "id": "<WORKSPACE_ID>"
                      }
                  },                
                  {
                      "action": [
                          "create"
                      ],
                      "subject": "files",
                      "conditions": {
                          "workspaceId": "<WORKSPACE_ID>"
                      }
                  }
              ],
              "subjectId": "<WORKSPACE_ID>",
              "subjectType": "workspaces"
          }
        ```

        See [RBAC for more advanced rules](/products/ai-builder/rbac)
      </Step>

      <Step title="Use the API Key">
        Include the API key in the x-prismeai-api-key header:

        ```bash theme={null}
        curl -X GET "https://api.studio.prisme.ai/v2/workspaces/{workspaceId}" \
             -H "Content-Type: application/json" \
             -H "x-prismeai-api-key: <apikey>"
        ```
      </Step>
    </Steps>

    <Info>
      API keys follow the principle of least privilege. They only have the permissions explicitly granted during creation.
    </Info>
  </Tab>
</Tabs>

## JWT Token Details

<Accordion title="JWT Structure and Signing">
  JWTs issued by Prisme.ai are signed tokens with the following characteristics:

  * **Algorithm**: Defined by `JWKS_ALG` (default: RS256)
  * **Key Type**: Defined by `JWKS_KTY` (default: RSA)
  * **Key Size**: Defined by `JWKS_SIZE` (default: 2048 bits)

  The JWT contains claims about the authenticated user, session, and permissions.

  Example decoded JWT payload:

  ```json theme={null}
    {
      "prismeaiSessionId": "session id",
      "jti": "...",
      "sub": "user id",
      "iat": 1744705420,
      "exp": 1747297420,
      "scope": "events:write events:read webhooks pages:read files:write files:read",
      "client_id": "prismeai-studio-client",
      "iss": "...",
      "aud": "..."
    }
  ```
</Accordion>

<Accordion title="JWT Key Rotation">
  The api-gateway automatically handles JWT key rotation:

  1. JWTs are signed using a JSON Web Key (JWK) that is stored in the api-gateway database
  2. JWKs are automatically rotated according to `JWKS_ROTATION_DAYS` (default: 30 days)
  3. When a JWK is rotated, it remains available for verification of existing JWTs
  4. Rotated JWKs are removed after `ACCESS_TOKENS_MAX_AGE` (default: 30 days) once all their signed JWTs should have expired
  5. Events (`gateway.jwks.updated` and `runtime.jwks.updated`) synchronize all api-gateway and runtime instances when JWKs are rotated or removed

  <Warning>
    If a signing JWK is compromised, it must be manually deleted from the database before restarting both api-gateway and runtime services.
  </Warning>
</Accordion>

<Accordion title="Public Keys">
  Public keys for verifying JWTs are available at:

  ```
  https://api.studio.prisme.ai/oidc/jwks
  ```

  This endpoint returns the public keys in JWKS (JSON Web Key Set) format, which can be used to verify token signatures.
</Accordion>

## Authentication Modes Summary

| Mode                     | Caller                | Token Format                                                |
| ------------------------ | --------------------- | ----------------------------------------------------------- |
| **User Session**         | Browser / frontend    | OIDC Bearer token or `access-token` cookie                  |
| **API Key**              | External integrations | `iak_{orgSlug}_{uuid}` in `x-prismeai-api-key` header       |
| **Access Token**         | Programmatic clients  | `at:` prefixed token in Authorization header                |
| **Cross-Workspace Call** | Other workspaces      | Identified by `run.sourceWorkspaceId` (injected by runtime) |

### Active Organization

Every authenticated user has an **active organization** that scopes permissions and resources. It is resolved on each request:

1. URL path (`/v2/orgs/:orgSlug/...`) takes priority
2. Then the session-persisted `activeOrgSlug`
3. Falls back to the user's first organization membership

Switch organizations with `PUT /v2/user/active-org`.

## Authentication Flow

1. **Client Authentication**: The client authenticates via OIDC or anonymous login to obtain a JWT
2. **API Gateway Validation**: Requests are sent to the api-gateway with the JWT or access token
3. **Header Transformation**: The api-gateway validates the token and adds an `x-prismeai-user-id` header
4. **Internal Routing**: The request is forwarded to the appropriate microservice with the user context
5. **Authorization Check**: The target microservice checks if the authenticated user has the required permissions

<Warning>
  Backend microservices rely on the `x-prismeai-user-id` header for identification. This header should not be directly set in client requests, as it will be overwritten by the api-gateway.
</Warning>

## Context Available in Automations

When building automations, the following context variables are available from the authenticated request:

### Session Context

| Variable                           | Description                            |
| ---------------------------------- | -------------------------------------- |
| `{{session.id}}`                   | Session ID                             |
| `{{session.org.slug}}`             | Active organization slug               |
| `{{session.org.name}}`             | Organization name                      |
| `{{session.org.role.slug}}`        | User's role slug in the active org     |
| `{{session.org.role.permissions}}` | Role permission strings (array)        |
| `{{session.org.role.scopes}}`      | Role scope strings (array)             |
| `{{session.org.groups}}`           | Groups the user belongs to in this org |
| `{{session.org.settings}}`         | Org settings (e.g. LLM governance)     |
| `{{session.org.subscription}}`     | Org subscription object                |

### User Context

| Variable            | Description                                                         |
| ------------------- | ------------------------------------------------------------------- |
| `{{user.id}}`       | User ID (read-only)                                                 |
| `{{user.email}}`    | User email                                                          |
| `{{user.role}}`     | Workspace CASL role (e.g. `owner`, `editor`) — **not** the org role |
| `{{user.orgSlugs}}` | Array of all org slugs the user belongs to (read-only)              |

### Run Context

| Variable                    | Description                                                                  |
| --------------------------- | ---------------------------------------------------------------------------- |
| `{{run.permissions}}`       | Org permissions as a nested object (`{product: {resource: {action: true}}}`) |
| `{{run.scopes}}`            | Raw scopes array from org role                                               |
| `{{run.correlationId}}`     | Request correlation ID                                                       |
| `{{run.sourceWorkspaceId}}` | Source workspace ID (for cross-workspace calls)                              |

<Note>
  `user.role` is the **workspace-level** role (from CASL security rules), not the organization role. The organization role is in `session.org.role`.
</Note>

## Token Security

<CardGroup cols="2">
  <Card title="Token Storage" icon="database">
    * Store tokens securely (not in localStorage for browser applications)
    * Use HttpOnly cookies where possible
    * For mobile apps, use secure storage mechanisms
    * For server applications, use environment variables or secure vaults
  </Card>

  <Card title="Token Transmission" icon="network-wired">
    * Always use HTTPS/TLS for API communication
    * Use Authorization header rather than query parameters
    * Don't include tokens in URLs or log them
    * Implement CSRF protection for cookie-based authentication
  </Card>

  <Card title="Token Management" icon="gear">
    * Implement token refresh strategies
    * Set appropriate token expiration times
    * Have processes for token revocation
    * Regularly rotate long-lived tokens
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation">
    * Handle 401 (Unauthorized) responses properly
    * Don't expose detailed error information to clients
    * Implement rate limiting for authentication failures
    * Log authentication failures for security monitoring
  </Card>
</CardGroup>

## Authentication Configuration

<Tabs>
  <Tab title="Environment Variables">
    JWT and authentication behavior can be configured with these environment variables:

    | Variable                | Description                    | Default Value     |
    | ----------------------- | ------------------------------ | ----------------- |
    | `JWKS_ROTATION_DAYS`    | Rotation period in days        | 30                |
    | `JWKS_KTY`              | JWK Algorithm family           | RSA               |
    | `JWKS_ALG`              | JWK signature algorithm        | RS256             |
    | `JWKS_SIZE`             | JWK size                       | 2048              |
    | `ACCESS_TOKENS_MAX_AGE` | JWT expiration time in seconds | 2592000 (30 days) |
  </Tab>

  <Tab title="Authorization Configuration">
    Each workspace manages its own permissions system using Role Based Access Control (RBAC).

    <Info>
      See the [Security](/api-reference/security) page for more details on the authorization system.
    </Info>
  </Tab>
</Tabs>

## Code Examples

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={null}
    const axios = require('axios');

    async function getPrismeData() {
      // Get or refresh your token using your authentication method
      const token = 'YOUR_ACCESS_TOKEN';
      
      try {
        const response = await axios.get('https://api.studio.prisme.ai/v2/workspaces', {
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token}`
          }
        });
        
        return response.data;
      } catch (error) {
        if (error.response && error.response.status === 401) {
          // Handle authentication error, potentially refresh token
          console.error('Authentication failed, token may be expired');
        } else {
          console.error('API request failed:', error.message);
        }
        throw error;
      }
    }
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    def get_prisme_data():
        # Get or refresh your token using your authentication method
        token = 'YOUR_ACCESS_TOKEN'
        
        headers = {
            'Content-Type': 'application/json',
            'Authorization': f'Bearer {token}'
        }
        
        try:
            response = requests.get('https://api.studio.prisme.ai/v2/workspaces', headers=headers)
            response.raise_for_status()  # Raise exception for HTTP errors
            return response.json()
        except requests.exceptions.HTTPError as err:
            if err.response.status_code == 401:
                # Handle authentication error, potentially refresh token
                print('Authentication failed, token may be expired')
            else:
                print(f'API request failed: {err}')
            raise
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    # Set your token as a variable
    TOKEN="YOUR_ACCESS_TOKEN"

    # Make API request
    curl -X GET "https://api.studio.prisme.ai/v2/workspaces" \
         -H "Content-Type: application/json" \
         -H "Authorization: Bearer $TOKEN"
    ```
  </Tab>
</Tabs>

## Next Steps

<CardGroup cols="3">
  <Card title="Error Handling" icon="triangle-exclamation" href="/api-reference/errors">
    Learn about common API errors and how to handle them
  </Card>

  <Card title="Rate Limits" icon="gauge-high" href="/api-reference/rate-limits">
    Understand the API's rate limiting policies
  </Card>

  <Card title="Security" icon="shield" href="/api-reference/security">
    Read about our security recommendations and best practices
  </Card>
</CardGroup>
