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

# Single Sign-On (SSO)

> Configure OIDC identity providers for user login

Adaptive Engine authenticates users through OpenID Connect (OIDC). You configure one or more identity providers, and users log in through your organization's existing identity system.

## How it works

When a user clicks "Log in" on the Adaptive Engine UI:

1. The browser redirects to your identity provider (Google, Azure Entra ID, Okta, etc.)
2. The user authenticates with their organization credentials
3. The provider redirects back to Adaptive Engine with an authorization code
4. Adaptive Engine exchanges the code for an ID token, extracts the user's email and name, and creates a session

The entire flow uses the Authorization Code grant with PKCE for security.

## Configuration

Configure OIDC providers in your Helm `values.yaml` under `secrets.auth.oidc.providers`. Each provider is an entry in the list:

```yaml theme={null}
secrets:
  auth:
    oidc:
      providers:
        - name: "Google"
          key: "google"
          issuer_url: "https://accounts.google.com"
          client_id: "your-client-id.apps.googleusercontent.com"
          client_secret: "your-client-secret"
          scopes: ["email", "profile"]
          pkce: true
          allow_sign_up: true
```

You can configure multiple providers. Each one appears as a separate login option on the sign-in page.

### Provider fields

| Field                    | Required | Default | Description                                                                                        |
| ------------------------ | -------- | ------- | -------------------------------------------------------------------------------------------------- |
| `name`                   | Yes      | —       | Display name on the login page                                                                     |
| `key`                    | Yes      | —       | URL-safe identifier (e.g., `google`, `azure-ad`). Must be unique across providers                  |
| `issuer_url`             | Yes      | —       | OIDC discovery endpoint. Adaptive Engine fetches `/.well-known/openid-configuration` from this URL |
| `client_id`              | Yes      | —       | OAuth2 client ID from your identity provider                                                       |
| `client_secret`          | No       | —       | OAuth2 client secret. Required by most providers, optional for public clients                      |
| `scopes`                 | Yes      | —       | OIDC scopes to request. Always include `email` and `profile`                                       |
| `pkce`                   | No       | `true`  | Enable Proof Key for Code Exchange. Keep enabled unless your provider does not support it          |
| `allow_sign_up`          | No       | `false` | Create new users on first login. When `false`, users must be pre-created via the SDK               |
| `allowed_domains`        | No       | `[]`    | Restrict login to specific email domains. Empty means all domains are allowed                      |
| `require_email_verified` | No       | `true`  | Reject users whose email is not verified by the provider                                           |

### Redirect URI

Set your identity provider's redirect URI to:

```
https://YOUR_DEPLOYMENT_URL/api/v1/auth/login/{key}/callback
```

Replace `{key}` with the provider key from your configuration (e.g., `google`, `okta`).

<Note>
  The `root_url` in your control plane configuration must match the public URL users access. OIDC redirects fail if this is misconfigured.
</Note>

## User provisioning

When a user logs in through OIDC for the first time, Adaptive Engine either finds an existing account or creates a new one (if `allow_sign_up: true`).

New users are assigned to the team and role defined in your auth configuration:

```yaml theme={null}
auth:
  default_team: "default"
  default_role: "read-only"
  admins: ["admin@company.com", "ops@company.com"]
```

| Field          | Description                                                                                                  |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
| `default_team` | Team assigned to new users on first login                                                                    |
| `default_role` | Role assigned within that team (see [Permissions](/v0.14/advanced/permissions))                              |
| `admins`       | Email addresses promoted to admin on first login. Set these **before** those users log in for the first time |

<Warning>
  If `allow_sign_up: true`, anyone who can authenticate with your OIDC provider can access Adaptive Engine. Use `allowed_domains` or set `allow_sign_up: false` and pre-create users via the SDK to restrict access.
</Warning>

## Security features

### PKCE

Proof Key for Code Exchange prevents authorization code interception attacks. Enabled by default and recommended for all providers. Only disable it if your provider explicitly does not support PKCE.

### Email domain restriction

Limit which email domains can log in per provider:

```yaml theme={null}
- name: "Corporate Google"
  key: "google"
  issuer_url: "https://accounts.google.com"
  client_id: "your-client-id"
  client_secret: "your-client-secret"
  scopes: ["email", "profile"]
  allowed_domains: ["company.com", "subsidiary.com"]
```

Users with emails outside these domains are rejected at login. Domain matching is case-insensitive.

### Email verification

By default, Adaptive Engine requires the OIDC provider to confirm the user's email is verified (`email_verified` claim). This prevents account hijacking through unverified email addresses.

Set `require_email_verified: false` only for development environments or providers that do not include the `email_verified` claim.

## Provider examples

### Google Workspace

1. Go to the [Google Cloud Console](https://console.cloud.google.com/apis/credentials)
2. Create an OAuth 2.0 client ID (application type: **Web application**)
3. Add `https://YOUR_DEPLOYMENT_URL/api/v1/auth/login/google/callback` as an authorized redirect URI
4. Copy the client ID and secret

```yaml theme={null}
- name: "Google"
  key: "google"
  issuer_url: "https://accounts.google.com"
  client_id: "123456789.apps.googleusercontent.com"
  client_secret: "GOCSPX-..."
  scopes: ["email", "profile"]
  pkce: true
  allow_sign_up: true
  allowed_domains: ["company.com"]
```

### Microsoft Entra ID (Azure AD)

1. In the [Azure Portal](https://portal.azure.com), go to **Entra ID** > **App registrations** > **New registration**
2. Set the redirect URI to `https://YOUR_DEPLOYMENT_URL/api/v1/auth/login/azure/callback` (type: **Web**)
3. Under **Certificates & secrets**, create a new client secret
4. Note the **Application (client) ID** and **Directory (tenant) ID**

```yaml theme={null}
- name: "Microsoft"
  key: "azure"
  issuer_url: "https://login.microsoftonline.com/YOUR_TENANT_ID/v2.0"
  client_id: "your-application-id"
  client_secret: "your-client-secret"
  scopes: ["email", "profile"]
  pkce: true
  allow_sign_up: true
```

Replace `YOUR_TENANT_ID` with your Azure directory tenant ID. Use `common` instead of a tenant ID to allow any Microsoft account.

### Okta

1. In the Okta Admin Console, go to **Applications** > **Create App Integration**
2. Select **OIDC - OpenID Connect** and **Web Application**
3. Set the sign-in redirect URI to `https://YOUR_DEPLOYMENT_URL/api/v1/auth/login/okta/callback`
4. Copy the client ID and secret from the application settings

```yaml theme={null}
- name: "Okta"
  key: "okta"
  issuer_url: "https://your-org.okta.com"
  client_id: "your-client-id"
  client_secret: "your-client-secret"
  scopes: ["email", "profile"]
  pkce: true
  allow_sign_up: true
```

If you use a custom authorization server, the issuer URL is `https://your-org.okta.com/oauth2/YOUR_AUTH_SERVER_ID`.

### Keycloak

1. In the Keycloak Admin Console, create a new client in your realm
2. Set **Client authentication** to **On** (confidential client)
3. Add `https://YOUR_DEPLOYMENT_URL/api/v1/auth/login/keycloak/callback` as a valid redirect URI
4. Copy the client ID and secret from the **Credentials** tab

```yaml theme={null}
- name: "Keycloak"
  key: "keycloak"
  issuer_url: "https://keycloak.company.com/realms/YOUR_REALM"
  client_id: "adaptive-engine"
  client_secret: "your-client-secret"
  scopes: ["email", "profile"]
  pkce: true
  allow_sign_up: true
```

### Amazon Cognito

1. In the [AWS Console](https://console.aws.amazon.com/cognito), create or select a User Pool
2. Under **App integration**, create an app client with a client secret
3. Add `https://YOUR_DEPLOYMENT_URL/api/v1/auth/login/cognito/callback` as a callback URL
4. Note the User Pool ID and region

```yaml theme={null}
- name: "Amazon Cognito"
  key: "cognito"
  issuer_url: "https://cognito-idp.REGION.amazonaws.com/POOL_ID"
  client_id: "your-client-id"
  client_secret: "your-client-secret"
  scopes: ["email", "profile"]
  pkce: true
  allow_sign_up: true
```

Replace `REGION` with your AWS region (e.g., `us-east-1`) and `POOL_ID` with your User Pool ID (e.g., `us-east-1_aBcDeFgHi`).

## Multiple providers

You can configure several providers at once. Each appears as a login option:

```yaml theme={null}
secrets:
  auth:
    oidc:
      providers:
        - name: "Corporate SSO"
          key: "azure"
          issuer_url: "https://login.microsoftonline.com/TENANT_ID/v2.0"
          client_id: "..."
          client_secret: "..."
          scopes: ["email", "profile"]
          allowed_domains: ["company.com"]
          allow_sign_up: true

        - name: "Partner Access"
          key: "okta"
          issuer_url: "https://partner-org.okta.com"
          client_id: "..."
          client_secret: "..."
          scopes: ["email", "profile"]
          allow_sign_up: false
```

This setup lets corporate users sign up automatically through Azure AD, while partner users must be pre-created via the SDK and can then log in through Okta.
