# Single Sign-On (SSO)

> Connect your identity provider (Entra ID/Azure AD, Okta, Google Workspace, or any OIDC/SAML IdP) so users sign in with corporate credentials, with group-to-role mapping.

Source: https://totalshiftleft.ai/help-center/product-documentation/single-sign-on

## Overview

This guide walks you through the **Single Sign-On** screen in Shift Left Studio exactly as it appears, from enabling SSO to testing a live login. An **SSO connection** lets your users sign in with corporate credentials from an OIDC or SAML identity provider (Microsoft Entra ID / Azure AD, Okta, Google Workspace, or any compliant IdP), and optionally maps IdP groups to app roles.

Explore the capability at [single sign-on](/features/collaboration-security/single-sign-on).

**Availability:** Enterprise.

## Before you begin

- You must be an administrator with the **manage_sso** permission. The connection-management endpoints require it; without it the screen won't load.
- Have your IdP details ready: for OIDC, the **Issuer URL**, **Client ID**, and **Client secret**; for SAML, the **Entry point (IdP SSO URL)** and the **IdP certificate (PEM)**.
- Navigate to **Settings → Access & Identity → Single Sign-On**.
- Secrets (**Client secret**, **SP private key**) are encrypted and shown **only once** — after you save, the field is replaced with a *configured* badge. Copy secrets into your IdP/records before saving.

## Step 1 — Enable Single Sign-On

1. On the **Single Sign-On** screen you'll see the subtitle *"Configure OIDC and SAML identity providers for your team."*
2. Find the **Enable Single Sign-On** card. When SSO is off, the helper text reads *"Turn on to configure OIDC / SAML identity providers for your team."*
3. Click the toggle switch on the right of that card. It flips to the active (blue) state and shows the notification **"Single Sign-On enabled."** The helper text changes to *"SSO is active. Add and manage identity providers below."*
4. If SSO is disabled you'll see a placeholder card: *"Single Sign-On is currently disabled. Use the switch above to enable it, then add an OIDC or SAML connection."* The **Add Connection** button only appears once SSO is enabled.

## Step 2 — Add a connection and fill the basics

1. Click **Add Connection** (top right). The form header reads **New Connection**.
2. Optionally click **Entra / Azure AD preset** (top right of the form) to pre-fill common OIDC values — it sets the protocol to OIDC, seeds the display name **Entra ID (Azure AD)**, the **Issuer URL** template `https://login.microsoftonline.com/<tenant>/v2.0`, and **Groups claim** `groups`.
3. Fill the basics grid:

| Field | What it does |
|-------|--------------|
| **Display name** | The connection's name (required), e.g. *Company SSO*. Saving with this blank shows **"Display name is required."** |
| **Protocol** | **OIDC (OpenID Connect)** or **SAML 2.0**. This choice decides which configuration block appears below. |
| **Default role** | Role assigned to users who sign in. Options: **Reader**, **Reviewer**, **Contributor**, **Administrator**, **Environment Manager**. |
| **Mapping mode** | **Additive (group mappings add to default role)** — group mappings grant extra access on top of the default role. **Authoritative (group mappings are the source of truth)** — group mappings alone determine roles. |
| **Enforced email domains (comma-separated)** | Only identities whose email domain is in this list may sign in, e.g. `example.com, corp.example.com`. A login from outside these domains is rejected with **DOMAIN_NOT_ALLOWED**. Leave blank to allow any domain. |
| **Connection enabled** | Checkbox. When checked the connection accepts logins. Uncheck to keep the connection configured but inactive. |

## Step 3a — OIDC configuration

If **Protocol** is **OIDC**, the **OIDC configuration** block appears:

| Field | What it does |
|-------|--------------|
| **Issuer URL** | Your IdP's issuer, e.g. `https://login.microsoftonline.com/<tenant>/v2.0`. |
| **Client ID** | The application/client ID registered in your IdP. |
| **Client secret** | The client secret from your IdP. Stored encrypted; once saved the label shows a green **configured** badge and the field placeholder becomes *"Leave blank to keep current."* Enter a new value only to change it. |
| **Scopes** | Space-separated scopes, default `openid profile email`. |
| **Groups claim** | The token claim carrying group membership, e.g. `groups`. Used by group mappings. |
| **Redirect URI** | The callback registered in your IdP, of the form `https://your-app/api/sso/<connectionId>/callback`. |

## Step 3b — SAML configuration

If **Protocol** is **SAML 2.0**, the **SAML configuration** block appears:

| Field | What it does |
|-------|--------------|
| **Entry point (IdP SSO URL)** | The IdP's SAML SSO endpoint, e.g. `https://idp.example.com/sso/saml`. |
| **Issuer (SP entity ID)** | This application's SAML entity ID (service-provider identifier). |
| **Groups attribute** | The SAML assertion attribute carrying groups, e.g. `http://schemas.xmlsoap.org/.../groups`. |
| **IdP certificate (PEM)** | The IdP's signing certificate, pasted in PEM form (starts with `-----BEGIN CERTIFICATE-----`). |
| **SP private key (PEM, optional — for signed requests)** | Optional private key so the app can sign SAML requests. Stored encrypted; once saved the label shows a **configured** badge and the placeholder becomes *"Leave blank to keep current."* |

## Step 4 — Add group mappings (optional)

Group mappings translate an IdP group into an app role. Under **Group mappings**, click **Add mapping** to add a row (the empty state reads *"No group mappings. Users get the default role above."*). Each row has:

| Field | What it does |
|-------|--------------|
| **IdP group** | The group id or name as it arrives from the IdP (via the Groups claim/attribute). A mapping with a blank **IdP group** is discarded on save. |
| **Grants role** | Role granted to members of that group: **—** (none), **Reader**, **Reviewer**, **Contributor**, **Administrator**, **Environment Manager**. |
| **Grant scope** | Where the role applies: **global**, **workspace**, or **project**. |
| **Target ID** | The workspace or project id the scope applies to (leave blank for global). |
| **Project role** | An optional named project role to grant. |

Use the trash icon to remove a mapping row.

## Step 5 — Create the connection

1. Click **Create Connection** at the bottom of the form (the button reads **Save Changes** when editing an existing connection). While saving it shows **Saving…**.
2. On success you'll see **"SSO connection created"** (or **"SSO connection updated"**) and the form closes.
3. The new connection appears in the list showing its **display name**, a **protocol** badge (OIDC/SAML), an **Enabled**/**Disabled** badge, and the line *"Default role: … · Mapping: …"*.

## Step 6 — Test login

1. In the connection's list row, click the **Test login** link — it points at `/api/sso/<connectionId>/login` and opens in a new tab.
2. You should be redirected to your IdP, sign in, and land back in the app. On success the app receives a token and completes login.
3. Manage a connection from its row: **Disable**/**Enable** (toggles the connection), the pencil icon (**Edit connection**), and the trash icon (**Delete connection**). Deleting prompts *"Delete SSO connection "…"? This cannot be undone."*

## Troubleshooting and notes

- **DOMAIN_NOT_ALLOWED (403)** — the signing-in user's email domain isn't in **Enforced email domains**. Add the domain or clear the field.
- **CONNECTION_NOT_FOUND (404)** — the connection is disabled or was deleted; only **enabled** connections accept logins.
- **INVALID_STATE / STATE_MISMATCH (400)** — the OIDC login state expired (10-minute limit) or was tampered with; start the login again.
- **SSO_CALLBACK_FAILED / SAML_CALLBACK_FAILED (401)** — the IdP response failed validation. Recheck **Issuer URL**/**Entry point**, **Client ID**, **Client secret**, and the **IdP certificate**.
- **CONNECTION_EXISTS (409)** — a connection with that identity already exists.
- Secrets (**Client secret**, **SP private key**) are never displayed again — the UI shows a *configured* badge. Leave a secret field blank when editing to keep the current value.
- All connection changes (create/update/delete) are written to the [audit log](/help-center/product-documentation/audit-logs).

## Related articles

- [Role Permissions](/help-center/product-documentation/role-permissions)
- [User Management](/help-center/product-documentation/user-management)
- [User Policies](/help-center/product-documentation/user-policies)
- [Audit Logs](/help-center/product-documentation/audit-logs)

