> ## 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 & SSO Integration

> Configure secure enterprise authentication for Prisme.ai with SSO options (OIDC and SAML)

Prisme.ai provides robust support for enterprise authentication requirements, allowing you to integrate with your existing identity providers through industry-standard protocols. This guide covers the configuration options for Single Sign-On (SSO) integration using OIDC and SAML.

## Platform SSO vs Organization SSO

Prisme.ai exposes **two levels** of SSO configuration, with the **same OIDC / SAML config format** in both cases — only the *place* where you declare it changes:

| Level                          | Where it's configured                                                                                                                          | Who sees it                                                                               | Auto-org membership                                                                 |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| **Platform SSO** *(this page)* | Kubernetes — `authProviders.config.yml` mounted into `prismeai-api-gateway`                                                                    | **Every user** at login (the SSO button is shown on the global sign-in page)              | No — users authenticate but are **not** automatically added to any organization     |
| **Organization SSO**           | Directly on the platform, via the **AI Governance** product — see [AI Governance — Identity & Access](/products/ai-governance/identity-access) | Users whose email matches an **organization-specific pattern** are redirected to that SSO | Yes — users are **automatically added** to the matching organization on first login |

Use **platform SSO** when you operate a single identity provider for all users of the platform. Use **organization SSO** when each organization brings its own identity provider and you want users to be onboarded into their org automatically. Both can coexist — platform SSO acts as the default, organization SSO overrides for users matching an org's email pattern.

The rest of this page covers the **platform** level. The config format (provider blocks, `attributesMapping`, etc.) shown below applies identically to organization SSO — you'll just paste it into the Governance UI instead of mounting a ConfigMap.

## Authentication Overview

Integrating your identity provider with Prisme.ai offers several benefits:

<CardGroup cols={2}>
  <Card title="Centralized Identity Management" icon="user-shield">
    Manage access through your existing identity provider
  </Card>

  <Card title="Enhanced Security" icon="shield-check">
    Enforce your organization's security policies and MFA requirements
  </Card>

  <Card title="Simplified User Experience" icon="hand-point-right">
    Provide one-click access without separate credentials
  </Card>

  <Card title="Automated Provisioning" icon="user-plus">
    Streamline user onboarding and offboarding
  </Card>
</CardGroup>

## Supported Authentication Methods

Prisme.ai supports the following authentication protocols:

<Tabs>
  <Tab title="OIDC">
    **OpenID Connect** is a modern authentication protocol built on top of OAuth 2.0.

    **Compatible with**:

    * Google Workspace
    * Okta
    * Auth0
    * Keycloak
    * Any standards-compliant OIDC provider
  </Tab>

  <Tab title="SAML">
    **Security Assertion Markup Language** is an XML-based authentication protocol.

    **Compatible with**:

    * ADFS
    * Okta
    * OneLogin
    * PingIdentity
    * Any standards-compliant SAML 2.0 provider

    **Current limitations**:

    * Only supports HTTP-POST binding for receiving authentication assertions
    * No support for IdP-initiated login
  </Tab>
</Tabs>

## Configuring OIDC Authentication

<Steps>
  <Step title="Register an Application">
    Create an OAuth 2.0 client in your OIDC provider.

    **Key configuration:**

    1. Register a **Web** OAuth2 client/app
    2. Configure the authorized redirect URI:
       ```
       https://API_URL/v2/login/callback
       ```
    3. Request the following scopes (minimum):
       ```
       openid email
       ```
    4. Add `profile` scope if you need first name and last name

    **Note the following credentials:**

    * Client ID
    * Client Secret
    * Auth URL (authorization\_endpoint)
    * Token URL (token\_endpoint)
    * Certificate URL (jwks\_uri)

    <Note>
      The JWKS URI might not be shown with client details as it is generally global to the IdP or tenant. This URL can return either a standard JWKS or an object mapping `kid`s to PEM certificate strings.

      Currently, only the **RS256** algorithm is supported.
    </Note>
  </Step>

  <Step title="Create Configuration File">
    Create an `authProviders.config.yml` file with your OIDC provider details.

    ```yaml theme={null}
    providers:
      <ProviderName>:
        type: oidc
        config:
          client_id: "your client id"
          client_secret: "your client secret"
          authorization_endpoint: "idp authorization_endpoint"
          token_endpoint: "idp token_endpoint"
          jwks_uri: "idp public certificates endpoint"
          scopes: "openid email profile"
          # issuer: "idp issuer URL"      # recommended; enforced during token exchange
          # allowTokenExchange: true      # opt-in: allow headless token exchange (see below)
        attributesMapping:
          firstName: 'given_name'
          lastName: 'family_name'
          email: 'email'
    ```

    <Warning>
      Choose your `<ProviderName>` carefully, as this name will be used in front-end services and injected into user authData, making it potentially difficult to change later.
    </Warning>

    * The `scopes` field is optional and defaults to `openid email`
    * The minimum required scopes are `openid` and `email`
    * Add `profile` scope to retrieve additional user attributes like name
  </Step>
</Steps>

## Token Exchange (headless clients)

By default an OIDC provider is used through the **browser redirect** flow (`/v2/login` → IdP → `/v2/login/callback`). For clients that have **already authenticated against the IdP** and hold an `id_token` — native and mobile apps, desktop clients, CLIs, server-to-server integrations — Prisme.ai can exchange that `id_token` directly for a nominative JWT, **with no browser**, via `POST /v2/login/token-exchange` (see [API Authentication](/api-reference/authentication)).

This is **disabled by default** and must be enabled per provider:

```yaml theme={null}
providers:
  <ProviderName>:
    type: oidc
    config:
      client_id: "your client id"
      jwks_uri: "idp public certificates endpoint"
      issuer: "idp issuer URL"        # strongly recommended
      allowTokenExchange: true        # enable headless token exchange
      # ... other OIDC fields
```

<Note>
  The exchanged `id_token` is verified against the provider's `jwks_uri`, and its `aud` claim **must** match `client_id`. Always set `issuer` so the `iss` claim is enforced too — without it, any token signed by the provider's keys and addressed to your `client_id` is accepted. Identity mapping (find-or-create user) is identical to the browser callback.
</Note>

<Info>
  If the provider is declared in `authProviders.config.yml`, set `allowTokenExchange` there and restart the api-gateway. If it is managed at the organization level via the API, an org **Owner** or **Admin** can update its `config` without a restart.
</Info>

<Warning>
  The endpoint is rate-limited per source IP via its **own** counter (`RATE_LIMIT_TOKEN_EXCHANGE`, default **60/min**), independent from anonymous logins. Because token exchange is usually brokered server-side, every end-user shares the same source IP — raise this limit for production deployments serving many users. See [Environment Variables](/self-hosting/kubernetes/environment-variables).
</Warning>

## Configuring SAML Authentication

<Steps>
  <Step title="Register Service Provider">
    Register Prisme.ai as a Service Provider (SP) in your Identity Provider.

    **Key configuration:**

    1. Configure the **ACS Endpoint**:
       ```
       https://API_URL/v2/login/callback
       ```
    2. Set the **SP EntityID** : must match the `audience` configured below
    3. Set **Name ID format** to `unspecified` (all formats are supported)

    **Export the IdP metadata XML file** containing the signing certificate and entity information.
  </Step>

  <Step title="Create Configuration File">
    Create an `authProviders.config.yml` file with your SAML provider details.

    ```yaml theme={null}
    providers:
      <ProviderName>:
        type: saml
        config:
          idp_metadata_filepath: "/path/towards/idp-saml-metadata.xml"
          audience: "Service Provider entity id"  
          issuer: "Issuer entity id, can be set to audience value"  
        attributesMapping:
          firstName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'
          lastName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'
          email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'
    ```

    <Warning>
      Choose your `<ProviderName>` carefully, as this name will be used in front-end services and injected into user authData, making it potentially difficult to change later.
    </Warning>

    If no XML file is available, you can configure individual parameters:

    ```yaml theme={null}
    providers:
      <ProviderName>:
        type: saml
        config:
          entryPoint: "https://idp.example.org/SAML2/SSO/Redirect"
          idpCert: "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----"
          audience: "Service Provider entity id"
          issuer: "Service Provider entity id"
    ```

    See [node-saml documentation](https://github.com/node-saml/node-saml) for complete configuration options.
  </Step>
</Steps>

## Mount Configuration File

Whether you configured an OIDC or SAML provider, you can now mount the configuration file inside the `prismeai-api-gateway` container at `/www/services/api-gateway/authProviders.config.yml`.\
You can customize the file location with the `AUTH_PROVIDERS_CONFIG` environment variable.

For **Kubernetes**, store the configuration file in a configmap :

<Tabs>
  <Tab title="OIDC (Google example)">
    ```yaml theme={null}
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: prismeai-api-gateway-authproviders
      namespace: core
    data:
      authProviders.config.yml: |
        # /www/services/api-gateway/authProviders.config.yml
        providers:
          google:
            type: oidc
            config:
              client_id: "CLIENT ID"
              client_secret: "CLIENT SECRET"
              authorization_endpoint: "https://accounts.google.com/o/oauth2/auth"
              token_endpoint: "https://oauth2.googleapis.com/token"
              jwks_uri: "https://www.googleapis.com/oauth2/v1/certs"
              scopes: "openid email profile"
            attributesMapping:
              firstName: 'given_name'
              lastName: 'family_name'
              email: 'email'
    ```
  </Tab>

  <Tab title="SAML">
    ```yaml theme={null}
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: prismeai-api-gateway-authproviders
      namespace: core
    data:
      authProviders.config.yml: |
        # /www/services/api-gateway/authProviders.config.yml
        providers:
          your-provider-name:
            type: saml
            config:
              idp_metadata_filepath: "/www/services/api-gateway/saml-FederationMetadata.xml"
              issuer: "issuer-id"
              audience: "issuer-id"
              skipRequestCompression: true
              wantAuthnResponseSigned: false
              identifierFormat: "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
            attributesMapping:
              firstName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'
              lastName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'
              email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'
      saml-FederationMetadata.xml: <EntityDescriptor ID="..."
        entityID="..." xmlns="urn:oasis:names:tc:SAML:2.0:metadata">...</EntityDescriptor>
    ```

    The IdP metadata XML is stored as a second key in the same ConfigMap, then mounted alongside `authProviders.config.yml` at the path referenced by `idp_metadata_filepath`.
  </Tab>
</Tabs>

<Note>
  Starting from **v27.2.8**, the providers config file supports environment variable interpolation through the `${SOME_ENV_VAR}` syntax. Any `${VAR}` placeholder is resolved against the `prismeai-api-gateway` container environment at startup.

  This is typically used to keep sensitive values (e.g. OIDC `client_id` / `client_secret`) out of the ConfigMap and inject them from Kubernetes secrets — including secrets synced from an external key vault (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, …) — while leaving the rest of the YAML static:

  ```yaml theme={null}
  providers:
    google:
      type: oidc
      config:
        client_id: "${GOOGLE_OIDC_CLIENT_ID}"
        client_secret: "${GOOGLE_OIDC_CLIENT_SECRET}"
        authorization_endpoint: "https://accounts.google.com/o/oauth2/auth"
        ...
  ```

  Then expose the corresponding env vars on the `prismeai-api-gateway` deployment (e.g. via `envFrom` / `secretKeyRef` pointing at your key vault-backed secrets).
</Note>

Add the following `volume` and `volumeMount` to `prismeai-api-gateway` deployment :

```yaml theme={null}
volumes:
  - name: gateway-authproviders
    configMap:
      name: prismeai-api-gateway-authproviders

volumeMounts:
  - name: gateway-authproviders
    mountPath: /www/services/api-gateway/authProviders.config.yml
    subPath: authProviders.config.yml
```

## Enable the Provider in UI

Sign-in buttons are rendered automatically by the frontend based on the SSO providers configured at the infrastructure level and in AI Governance. There is nothing to configure on the UI side : any provider declared in your config file will appear on the sign-in page using the `label` and `icon` defined there.

## Disable local sign-in and sign-up

You can restrict local authentication using the following environment variables on `prismeai-api-gateway` :

```
DISABLE_LOCAL_SIGNIN='true'
DISABLE_LOCAL_SIGNUP='true'
```

* `DISABLE_LOCAL_SIGNIN` disables the local username/password sign-in API. Only SSO providers remain available to log in.
* `DISABLE_LOCAL_SIGNUP` disables the local sign-up API. Existing local users can still sign in (unless `DISABLE_LOCAL_SIGNIN` is also set), but no new local account can be created.

## Multi-Factor Authentication (MFA)

Prisme.ai enforces **TOTP** (Time-based One-Time Password, [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)) multi-factor authentication for **local (password) accounts**. This is the standard "authenticator app" method — users scan a QR code with Google Authenticator, Microsoft Authenticator, Authy, 1Password, etc., then enter a 6-digit code.

<Note>
  MFA applies **only to local accounts**. SSO accounts are exempt — their identity provider already enforces its own second factor. Anonymous sessions are also exempt.
</Note>

### Enabling / disabling

MFA for local accounts is controlled by a single environment variable on `prismeai-api-gateway`:

```
MFA_FORCE_LOCAL='true'   # default
```

* **`true` (default)** — every local account must complete TOTP. Set it to `false` to disable platform-enforced MFA.

### User experience

The factor is requested **after** a valid password sign-in, before the app loads:

1. **First sign-in (enrollment)** — the user confirms their password, scans the displayed QR code (or enters the secret key manually) with their authenticator app, then enters the generated 6-digit code.
2. **Subsequent sign-ins (challenge)** — the user enters the current 6-digit code from their authenticator app.

<Info>
  **Existing local users are migrated lazily.** When you enable `MFA_FORCE_LOCAL`, current users are not locked out and no database migration is required — each user simply enrolls an authenticator on their next sign-in.
</Info>

### SSO + local on the same deployment

The local/SSO distinction is based on whether the account has a **local password**:

* A **pure SSO user** (created via an identity provider, no local password) is never prompted for TOTP.
* A **local user** (password) must complete TOTP.

<Warning>
  Do **not** configure an SSO provider with the slug `prismeai`. That slug is reserved for the built-in local (password) provider. An SSO provider named `prismeai` would make its users look like local accounts and force them into TOTP enrollment — which they cannot complete (enrollment requires the current password), resulting in a lockout. Use any other slug for federation (e.g. `prisme-saas`, `prisme-client`).
</Warning>

## Custom Attribute Mapping

All authentication methods support mapping identity provider attributes to Prisme.ai user properties:

<Accordion title="Attribute Mapping Configuration">
  The `attributesMapping` section in your provider configuration maps provider-specific attributes to standard Prisme.ai fields.

  ```yaml theme={null}
  providers:
    <ProviderName>:
      type: oidc  # or saml
      # ... other config ...
      attributesMapping:
        firstName: 'provider_first_name_field'
        lastName: 'provider_last_name_field'
        email: 'provider_email_field'
  ```

  Only `firstName`, `lastName`, and `email` are supported as native fields.

  **Common OIDC Mappings:**

  ```yaml theme={null}
  attributesMapping:
    firstName: 'given_name'
    lastName: 'family_name'
    email: 'email'
  ```

  **Common SAML Mappings:**

  ```yaml theme={null}
  attributesMapping:
    firstName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'
    lastName: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname'
    email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'
  ```

  You can inspect available attributes by examining `gateway.login.succeeded` events or by reading the `{{user}}` variable from a test automation.
</Accordion>

## Troubleshooting

<Accordion title="Common Issues and Solutions">
  **1. Redirect URI Mismatch**

  **Symptom:** Error message about redirect URI not matching during authentication

  **Solution:**

  * Ensure the redirect URI in your IdP exactly matches `https://API_URL/v2/login/callback` for OIDC/SAML or `https://API_URL/v2/login/azure/callback` for Microsoft
  * Check for trailing slashes or HTTP vs HTTPS mismatches

  **2. JWKS Retrieval Failed**

  **Symptom:** Authentication fails with JWKS errors

  **Solution:**

  * Verify the `jwks_uri` endpoint is accessible from the Prisme.ai server
  * Check for correct formatting of the JWKS endpoint URL
  * Ensure the signing algorithm is RS256

  **3. SAML Response Validation Failed**

  **Symptom:** SAML authentication fails after IdP redirect

  **Solution:**

  * Confirm the IdP certificate in the configuration is correct and not expired
  * Verify the IdP is sending responses via HTTP-POST binding
  * Check that the `issuer` value matches the EntityID expected by the IdP
  * Try adding `skipRequestCompression: true` and `wantAuthnResponseSigned: false` SAML options

  **4. Missing User Attributes**

  **Symptom:** User logs in successfully but name fields are empty

  **Solution:**

  * Check that the `attributesMapping` configuration matches the actual attribute names provided by your IdP
  * For OIDC, ensure the `profile` scope is requested if you need name attributes
  * Examine the authentication events to see what claims are actually being received
</Accordion>

<Accordion title="Diagnostic Tools">
  **Event Logs**

  Authentication issues can be diagnosed by examining events in the Activity view:

  * Look for `gateway.login.started` events to see authentication attempts
  * Check `gateway.login.succeeded` events to examine the received user claims
  * Investigate `gateway.login.failed` events for error details

  **Configuration Testing**

  You can validate your SSO configuration by:

  1. Creating a test user in your IdP
  2. Attempting authentication with detailed logs enabled
  3. Examining the request/response data in the Activity logs

  **Common Error Codes**

  * `invalid_request`: Malformed authentication request
  * `unauthorized_client`: The client is not authorized for the requested authentication flow
  * `access_denied`: The resource owner denied the request
  * `invalid_token`: JWT validation failed
  * `invalid_grant`: The provided authorization grant is invalid
</Accordion>

## Security Considerations

<CardGroup cols={2}>
  <Card title="Token Validation" icon="shield-check">
    * Always validate JWT signatures using the IdP's public keys
    * Verify token expiration and issuance times
    * Confirm the audience and issuer claims match your application
  </Card>

  <Card title="Secure Storage" icon="key">
    * Store client secrets securely using environment variables or secrets management
    * Never hardcode secrets in configuration files or source code
    * Rotate secrets periodically according to your security policy
  </Card>

  <Card title="TLS Encryption" icon="lock">
    * Ensure all authentication traffic uses HTTPS
    * Configure proper TLS versions and cipher suites
    * Validate certificates in production environments
  </Card>

  <Card title="Access Controls" icon="user-lock">
    * Implement proper RBAC after authentication
    * Don't assume authenticated users should have access to all resources
    * Regularly audit user access and permissions
  </Card>
</CardGroup>
