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

# Enterprise SSO

> Connect your organization's identity provider — Okta, Entra ID, Auth0, Google Workspace — via OAuth2/OIDC.

Enterprise single sign-on lets your organization's users sign in to Pria with the same credentials they already use for email, payroll, and every other internal app. Pria delegates authentication to your identity provider (IdP); the IdP enforces password policy, MFA, conditional access, and account lifecycle, and tells Pria who the user is.

Each SSO provider is configured per **institution** in Pria. Users land on a per-institution login URL — `https://your-domain.com/sso/<slug>` — and from there are redirected straight to the IdP.

***

## What enterprise SSO does for you

* **Single sign-on across your organization.** If the user is already signed in at the IdP, they reach Pria without seeing a Pria login form.
* **Centralised account lifecycle.** Disable the user at the IdP and they can no longer reach Pria. No Pria-side password to rotate.
* **IdP-enforced security.** MFA, conditional access, IP allowlists, and device posture are all evaluated at the IdP. Pria inherits whatever the IdP says.
* **Just-in-time user provisioning.** The first time a user signs in with SSO, Pria automatically creates their account and enrols them in the linked institution. No bulk import step required.

***

## Supported protocols

| Protocol                              | Status              | Notes                                                                                                        |
| ------------------------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------ |
| **OAuth 2.0 / OpenID Connect (OIDC)** | Supported, built-in | The flow described on this page. Works with any OIDC-conformant IdP.                                         |
| **SAML 2.0**                          | Enterprise feature  | Contact the Praxis AI team at [humans@praxis-ai.com](mailto:humans@praxis-ai.com) for SAML 2.0 requirements. |
| **SCIM 2.0** (provisioning)           | Enterprise feature  | Contact the Praxis AI team at [humans@praxis-ai.com](mailto:humans@praxis-ai.com) for SCIM provisioning.     |

For OAuth2/OIDC, Pria runs the Authorization Code flow: the user is redirected to the IdP, signs in, and is redirected back with a one-time `code`. Pria exchanges the code for an access token server-to-server and reads the user profile from the IdP's `userinfo` endpoint.

***

## Setting up an OAuth2 / OIDC provider

<Steps>
  <Step title="Register Pria as an application in your IdP">
    In your IdP's admin console, create a new **OIDC web application** (sometimes called *Web App*, *Regular Web Application*, or *Confidential Client*). You'll get back a **Client ID** and **Client Secret**.

    Register Pria's callback URL with the IdP:

    ```
    https://your-domain.com/sso/<slug>
    ```

    Where `<slug>` is the short identifier you'll choose in step 2 (e.g. `acme-okta`, `myuniversity`). The callback URL must match **exactly** what you'll register on the Pria side, including capitalisation and trailing characters.
  </Step>

  <Step title="Create the provider in Pria">
    In Pria, go to **Admin → SSO Providers** and click **Add SSO Provider**. (You need the `sso.add` admin entitlement — see [SSO Providers](/mdx/admin-guide/sso-providers).)

    Pick the **institution** this provider belongs to. Each institution can have one SSO provider.
  </Step>

  <Step title="Set the slug and label">
    | Field     | What it is                                                            | Example     |
    | --------- | --------------------------------------------------------------------- | ----------- |
    | **Slug**  | URL-friendly id (lowercase, numbers, hyphens). Becomes the login URL. | `acme-okta` |
    | **Label** | Human-friendly name shown in the admin UI.                            | `Acme Okta` |

    The slug is the public route: users will sign in at `https://your-domain.com/sso/acme-okta`.
  </Step>

  <Step title="Configure the OAuth2 endpoints">
    | Field              | Description                                                            | Default             |
    | ------------------ | ---------------------------------------------------------------------- | ------------------- |
    | **Client ID**      | OAuth client ID from your IdP                                          | —                   |
    | **Client Secret**  | OAuth client secret from your IdP. Stored encrypted, masked in the UI. | —                   |
    | **Token Host**     | Base URL for the IdP's OAuth endpoints                                 | —                   |
    | **Token Path**     | Path appended to Token Host for the token exchange                     | `/oauth2/token`     |
    | **Authorize Path** | Path appended to Token Host for the authorize redirect                 | `/oauth2/authorize` |
    | **User Info URL**  | Full URL of the OIDC `userinfo` endpoint                               | —                   |
    | **Scope**          | OAuth scope requested at sign-in                                       | `openid`            |
  </Step>

  <Step title="Configure field mapping">
    Pria reads three fields from the IdP's `userinfo` response: email, first name, last name. Defaults match standard OIDC claims:

    | Pria field           | Default IdP claim |
    | -------------------- | ----------------- |
    | `email`              | `email`           |
    | `fname` (first name) | `given_name`      |
    | `lname` (last name)  | `family_name`     |

    Override these only if your IdP uses non-standard claim names (e.g. `mail` instead of `email`, `firstName` instead of `given_name`).

    <Warning>An incorrect email mapping is the #1 SSO setup failure. If the IdP returns `null` for whatever Pria thinks is the email claim, account creation fails with a confusing "invalid account" error.</Warning>
  </Step>

  <Step title="Enable and test">
    Toggle **Enabled** on, save, and visit `https://your-domain.com/sso/<slug>` in an incognito window. You should be redirected to the IdP, sign in, and land back in Pria.

    Use the **Test** button in the admin UI to verify connectivity to the Token Host before doing the round-trip test.
  </Step>
</Steps>

***

## Just-in-time user provisioning

When a user signs in via SSO and Pria doesn't have a matching account, it creates one **automatically** using the email returned by the IdP and enrols the user in the institution attached to the SSO provider. No bulk import or pre-provisioning step is required.

If an account with that email already exists (e.g. the user previously signed up with email + password), it's reused — the SSO sign-in becomes another login method for the same account, and the user is enrolled in the institution.

<Info>Just-in-time provisioning only creates **the user record**. It does not assign admin entitlements. New users are normal members of the institution; an existing admin must promote them if needed.</Info>

***

## Disabling a provider without deleting it

You can flip the **Enabled** toggle off at any time. The provider configuration is preserved (client ID, secret, endpoint URLs, field mapping) but the SSO URL stops working: visitors see a red banner reading `SSO provider '<slug>' is currently disabled`.

This is the right move for an emergency shutoff, a maintenance window, or while you migrate the IdP-side configuration. To re-enable, just flip the toggle back on.

Deleting the provider entirely removes the configuration. Existing SSO-provisioned users keep their Pria accounts — they just can't sign in via this provider anymore. They can still sign in by any other method tied to their email (e.g. a password they set, social login).

***

## Multiple SSO providers per institution

Each institution can have one SSO provider configured at a time. If your institution needs to authenticate via two different IdPs (e.g. an Okta tenant for staff and a separate Auth0 tenant for contractors), the standard pattern is to:

1. Create two **separate institutions** in Pria, one per IdP.
2. Attach a different SSO provider to each.
3. Decide whether to grant some users membership in both institutions, depending on access requirements.

For more complex multi-IdP setups, contact the Praxis AI team at [humans@praxis-ai.com](mailto:humans@praxis-ai.com).

***

## Sample IdP setups

<AccordionGroup>
  <Accordion title="Okta (OIDC)">
    1. In the Okta admin console, **Applications → Create App Integration → OIDC - OpenID Connect → Web Application**.
    2. **Sign-in redirect URIs:** `https://your-domain.com/sso/<slug>`.
    3. **Grant type:** Authorization Code (enabled by default).
    4. Copy the **Client ID** and **Client Secret** from the app's General tab.

    Pria settings:

    | Pria field     | Value                                             |
    | -------------- | ------------------------------------------------- |
    | Token Host     | `https://your-tenant.okta.com`                    |
    | Token Path     | `/oauth2/v1/token`                                |
    | Authorize Path | `/oauth2/v1/authorize`                            |
    | User Info URL  | `https://your-tenant.okta.com/oauth2/v1/userinfo` |
    | Scope          | `openid profile email`                            |

    Default field mapping (`email`, `given_name`, `family_name`) works as-is with Okta.
  </Accordion>

  <Accordion title="Microsoft Entra ID (formerly Azure AD)">
    1. In the Entra admin centre, **App registrations → New registration**. Set **Redirect URI (Web)** to `https://your-domain.com/sso/<slug>`.
    2. Under **Certificates & secrets**, create a new client secret. Copy the value immediately — it isn't shown again.
    3. Under **API permissions**, add Microsoft Graph delegated permissions: `openid`, `profile`, `email`.
    4. Note the **Application (client) ID** and the **Directory (tenant) ID**.

    Pria settings:

    | Pria field     | Value                                       |
    | -------------- | ------------------------------------------- |
    | Token Host     | `https://login.microsoftonline.com`         |
    | Token Path     | `/<tenant-id>/oauth2/v2.0/token`            |
    | Authorize Path | `/<tenant-id>/oauth2/v2.0/authorize`        |
    | User Info URL  | `https://graph.microsoft.com/oidc/userinfo` |
    | Scope          | `openid profile email`                      |

    Default field mapping works for Entra ID's OIDC userinfo response.
  </Accordion>

  <Accordion title="Auth0">
    1. In the Auth0 dashboard, **Applications → Create Application → Regular Web Applications**.
    2. **Allowed Callback URLs:** `https://your-domain.com/sso/<slug>`.
    3. Copy the **Client ID** and **Client Secret** from the application's Settings tab.

    Pria settings:

    | Pria field     | Value                                    |
    | -------------- | ---------------------------------------- |
    | Token Host     | `https://your-tenant.auth0.com`          |
    | Token Path     | `/oauth/token`                           |
    | Authorize Path | `/authorize`                             |
    | User Info URL  | `https://your-tenant.auth0.com/userinfo` |
    | Scope          | `openid profile email`                   |

    Default field mapping works with Auth0.
  </Accordion>

  <Accordion title="Google Workspace (OIDC)">
    1. In [Google Cloud Console → APIs & Services → Credentials](https://console.cloud.google.com/apis/credentials), create an **OAuth 2.0 Client ID** of type *Web application*.
    2. **Authorized redirect URIs:** `https://your-domain.com/sso/<slug>`.
    3. Copy the **Client ID** and **Client Secret**.

    Pria settings:

    | Pria field     | Value                                                     |
    | -------------- | --------------------------------------------------------- |
    | Token Host     | `https://oauth2.googleapis.com`                           |
    | Token Path     | `/token`                                                  |
    | Authorize Path | `https://accounts.google.com/o/oauth2/v2/auth` (full URL) |
    | User Info URL  | `https://www.googleapis.com/oauth2/v2/userinfo`           |
    | Scope          | `openid profile email`                                    |

    For a simpler integration that also lets users authorise Gmail/Drive/Calendar, prefer the [Google Workspace integration](/mdx/integrations/google-workspace/overview) — it covers more ground than a vanilla OIDC SSO setup.
  </Accordion>
</AccordionGroup>

***

## Common errors

| Symptom                                                     | Likely cause                                                                                     | Fix                                                                                    |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
| `invalid_grant` on callback                                 | Redirect URL registered with the IdP does not match `https://your-domain.com/sso/<slug>` exactly | Re-register the redirect URL; check protocol, host, slug, trailing characters          |
| `Authentication request validation failed` (state mismatch) | The user opened a stale tab and tried to complete a sign-in 5+ minutes after starting it         | Restart sign-in from the login URL                                                     |
| `SSO provider '<slug>' is currently disabled`               | Provider exists but the **Enabled** toggle is off                                                | Re-enable in admin, or use a different provider                                        |
| `SSO provider '<slug>' not found`                           | Slug in the URL does not match any configured provider                                           | Check the slug spelling; check the right institution is selected                       |
| User gets created but with no name                          | IdP returns custom claim names instead of `given_name` / `family_name`                           | Adjust **Field Mapping** in the provider config                                        |
| User gets created with email `null@undefined`               | IdP did not return an `email` claim, or returned a different claim name                          | Add `email` (or equivalent) to the requested **Scope**; adjust the email field mapping |
| Callback returns `invalid_callback` from the IdP            | The redirect URL Pria sends does not match what the IdP has on file                              | Match the URL exactly, character for character                                         |

For other failures, look at the IdP-side log first — it will tell you whether the token request even reached the IdP and what was wrong with it.

***

## Related

* [SSO Providers (admin)](/mdx/admin-guide/sso-providers)
* [Authentication Overview](/mdx/integrations/authentication/overview)
* [Social Login (Google, GitHub, Facebook)](/mdx/integrations/authentication/social-oauth)
* [Google Workspace integration](/mdx/integrations/google-workspace/overview)
