# Enterprise SSO

> Connect your customers' identity providers (Microsoft Entra ID, Okta, Google Workspace, any OIDC provider) with email-domain routing.

Source: https://9in.io/docs/enterprise-sso/

Enterprise SSO lets the employees of your business customers sign in with their company account: Microsoft Entra ID, Okta, Google Workspace, ADFS 2016+, Keycloak, Ping, Auth0 or any OpenID Connect provider. Users are routed by their email domain, so `jane@bigcorp.com` goes straight to BigCorp's identity provider.

9in connects over **OpenID Connect**. SAML is not supported; every major enterprise IdP also offers OIDC.

## Add a connection

Your customer creates an application ("app registration") in their identity provider, with this redirect URI:

```text
https://acme.9in.io/oauth/enterprise/callback
```

and gives you its **issuer URL**, **client ID** and **client secret**. Then in the console, **Connections → Enterprise SSO → Add connection**:

| Field | Example | Notes |
|---|---|---|
| Display name | BigCorp | Shown on the sign-in button |
| Connection ID | `bigcorp` | Lowercase; appears in URLs and as `enterprise:bigcorp` in user identities |
| Issuer URL | `https://login.microsoftonline.com/<tenant-id>/v2.0` | Must serve `/.well-known/openid-configuration` over https |
| Client ID / secret | | The secret is stored encrypted |
| Email domains | `bigcorp.com` | Users typing an address at these domains go straight to this provider (home realm discovery) |
| Extra scopes | `groups` | Added to `openid email profile` |
| Show a button | on | Otherwise reachable only by email domain |
| Link existing accounts by email | on | Only for addresses at the connection's domains |

ID tokens from the provider are fully verified against its keys (signature, issuer, audience, nonce).

## Email domains and trust

The connection is authoritative for its **email domains**: an email at one of them is treated as verified, and (with linking on) links to an existing user with that email. Emails at other domains are kept as the provider sent them and never link. Only list domains the customer actually owns.

## Microsoft Entra ID

- Use the directory (tenant) ID or one of its domains in the issuer, with `/v2.0` at the end: `https://login.microsoftonline.com/<tenant-id>/v2.0`. `common` and `organizations` don't work for a single customer: for any Microsoft account, turn on Microsoft under [social login](https://9in.io/docs/social-login/) instead.
- **Entra External ID** (the successor to Azure AD B2C) works with its issuer, `https://<tenant-id>.ciamlogin.com/<tenant-id>/v2.0`.
- Work accounts carry no `email` claim unless the app registration adds it as an optional claim (**Token configuration → email**). Without it, 9in uses the user's sign-in name (UPN) when it's in one of the connection's domains, which Entra only allows for verified domains.
- Client secrets expire after at most 24 months. Note the date and update the secret in the console before then.

## Okta, Google Workspace and others

| Provider | Issuer |
|---|---|
| Okta | `https://<org>.okta.com` (or `https://<org>.okta.com/oauth2/default` for a custom authorization server) |
| Google Workspace | `https://accounts.google.com` (with an *internal* OAuth client in the customer's Google Cloud project) |
| Auth0 | `https://<tenant>.auth0.com/` |
| Keycloak | `https://sso.example.com/realms/<realm>` |
| ADFS 2016+ | `https://adfs.example.com/adfs` |

## What users see

On the sign-in page they type their work email; 9in recognises the domain and sends them to their company's sign-in, then back to your app. With **Show a button**, a "Continue with BigCorp" button is shown too. Enterprise users get `fed` in the ID token's `amr` claim and `enterprise:<connection id>` among their identities.

## Troubleshooting

When a connection fails, the user sees a "sign-in didn't complete" page and the reason is in the console's **Activity** log (`enterprise.error`): issuer mismatch, a wrong secret, a redirect URI the provider doesn't know, and so on.
