From 5e845962c4b781f88f8836eb50137b01d20ed652 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:03:51 +0200 Subject: [PATCH 01/12] docs: add single sign-on guide for SSO administrators Internet Identity can authenticate an organization's staff against its own OpenID provider, but nothing documented how to set that up. The new page is written for the administrator of the identity provider: register a client, publish the discovery file, and optionally govern access per application. Also adds the application developer's side to the Internet Identity page: the `ssoDomain` option, validating a user-typed domain with `isValidSsoDomain`, and SSO-scoped attributes. The two pages link to each other. Co-Authored-By: Claude Opus 5 (1M context) --- .../authentication/internet-identity.mdx | 47 +++++ docs/guides/authentication/single-sign-on.md | 168 ++++++++++++++++++ .../authentication/verifiable-credentials.md | 2 +- 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 docs/guides/authentication/single-sign-on.md diff --git a/docs/guides/authentication/internet-identity.mdx b/docs/guides/authentication/internet-identity.mdx index 9bf736f7..e53f0aac 100644 --- a/docs/guides/authentication/internet-identity.mdx +++ b/docs/guides/authentication/internet-identity.mdx @@ -129,6 +129,39 @@ const authClient = new AuthClient({ The rest of the flow (`signIn`, `getIdentity`, `signOut`) is unchanged. +### One-click SSO sign-in + +To send the user to their organization's own OpenID provider instead, pass `ssoDomain` with the organization's domain. Internet Identity resolves the provider from a configuration file the organization publishes on that domain, so nothing has to be registered on either side: + +```javascript +const authClient = new AuthClient({ + identityProvider: getIdentityProviderUrl(), + ssoDomain: "acme.com", +}); +``` + +`openIdProvider` and `ssoDomain` are mutually exclusive. Each picks a different provider for the same sign-in, so setting both throws. + +If the domain comes from the user rather than your own configuration, validate it first. `isValidSsoDomain` checks that the domain is well-formed and that it publishes an SSO configuration: + +```javascript +import { isValidSsoDomain } from "@icp-sdk/auth/client"; + +const controller = new AbortController(); + +if (await isValidSsoDomain(domainInput.value, controller.signal)) { + const authClient = new AuthClient({ + identityProvider: getIdentityProviderUrl(), + ssoDomain: domainInput.value, + }); + await authClient.signIn(); +} +``` + +Call `controller.abort()` when the input changes. An aborted check rejects instead of returning `false`, so a superseded check is never read as an invalid domain. The check also never resolves in under 750 ms, which keeps a partially typed domain from flashing an error on every keystroke. + +For what an organization publishes to make this flow work, see [Single sign-on](single-sign-on.md). + ### Create an authenticated agent After sign-in, create an `HttpAgent` using the delegation identity. The agent signs all subsequent canister calls with the user's delegated key: @@ -233,6 +266,19 @@ const attributesPromise = authClient.requestAttributes({ }); ``` +#### SSO-scoped attributes + +Attributes work the same way for an SSO sign-in, scoped to the organization's domain instead of a provider issuer: + +```typescript +const attributesPromise = authClient.requestAttributes({ + keys: scopedKeys({ ssoDomain: "acme.com", keys: ["name", "email"] }), + nonce: noncePromise, +}); +``` + +They arrive in the bundle as `sso:acme.com:name` and `sso:acme.com:email`. Only those two keys are available: `verified_email` is not, because Internet Identity has no basis to confirm that a user has access to an address asserted by another organization's provider. + ## Backend authentication Your backend canister receives the caller's principal automatically through the IC protocol. You do not pass the principal as a function argument: use `msg.caller` (Motoko) or `ic_cdk::api::msg_caller()` (Rust) to read it. @@ -617,6 +663,7 @@ For full details, see the [Internet Identity specification](../../references/int ## Next steps +- [Single sign-on](single-sign-on.md) for connecting an organization's own OpenID provider, from the administrator's side - [Wallet integration](../digital-assets/wallet-integration.md) for token-based authentication alternatives - [Frontend frameworks](../frontends/frameworks.md) for framework-specific auth setup patterns - [Internet Identity specification](../../references/internet-identity-spec.md) for protocol details and the full alternative origins spec diff --git a/docs/guides/authentication/single-sign-on.md b/docs/guides/authentication/single-sign-on.md new file mode 100644 index 00000000..c58013c1 --- /dev/null +++ b/docs/guides/authentication/single-sign-on.md @@ -0,0 +1,168 @@ +--- +title: "Single sign-on" +description: "Connect your organization's OpenID provider to Internet Identity so staff sign in to ICP applications with their company account, and control access per application." +sidebar: + order: 2 +--- + +Internet Identity can authenticate your staff against your own OpenID Connect provider (Okta, Entra ID, Google Workspace, Auth0, Keycloak, or any other OIDC-compliant IdP). Staff enter your company domain on the Internet Identity sign-in screen and authenticate with their existing company account. + +This guide is for the administrator of the identity provider. Two steps switch it on for the whole organization, and an optional third step controls access application by application. No registration with Internet Identity is required: it discovers your configuration from a file you publish on your domain. + +If you are building an application and want to send users into this flow, see [Internet Identity](internet-identity.md). + +## How it works + +1. A user picks **Continue with SSO** on the Internet Identity sign-in screen and enters your company domain, for example `acme.com`. +2. Internet Identity fetches `https://acme.com/.well-known/ii-openid-configuration` and reads the OIDC client to use. +3. It follows the `openid_configuration` URL in that file to your provider's standard OIDC discovery document, which supplies the issuer, the authorization endpoint, and the signing keys. +4. The user authenticates with your provider. Your provider returns an ID token. +5. Internet Identity verifies that token against your provider's published keys and issues the user a delegation for the application they are signing in to. + +Verification happens onchain, in the Internet Identity canister. Your provider's signing keys are fetched by the network, not by the user's browser, and the token never has to be trusted by the application. + +## Step 1: Register an OIDC client + +In your identity provider, create an application integration of type **OIDC / Web application**, configured as follows. + +| Setting | Value | +|---------|-------| +| Redirect URI | `https://id.ai/callback` | +| Grant types | Authorization code **and** implicit (the hybrid flow) | +| ID token | Allowed with the implicit grant | +| Access token | Not required. Leave it unchecked | +| Scopes | `openid`, `profile`, `email` | + +Internet Identity uses `response_type=code id_token` with `response_mode=form_post`, and verifies the ID token in the canister. There is no token-endpoint exchange, so a client restricted to the authorization-code flow alone cannot be used. A client that does not allow an ID token with the implicit grant produces an `unsupported_response_type` error on the sign-in screen. + +Copy the client ID when you are done. You need it in step 2. + +## Step 2: Publish the discovery file + +Serve the following document over HTTPS at exactly this path on your company domain: + +``` +https://acme.com/.well-known/ii-openid-configuration +``` + +```json +{ + "client_id": "0oaDEFAULT", + "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", + "name": "Acme Corp" +} +``` + +| Field | Required | Meaning | +|-------|----------|---------| +| `client_id` | Yes | The client from step 1. Every ID token's `aud` claim must match it | +| `openid_configuration` | Yes | Your provider's OIDC discovery URL. Must be `https` | +| `name` | No | Label shown on the sign-in screen and on consent prompts. Falls back to the domain. Maximum 255 bytes | +| `app_clients` | No | Per-application access control. See step 3 | +| `gate_all_apps` | No | Deny applications not listed in `app_clients`. Defaults to `false` | +| `stable_identifier_claim` | No | Claim used as the stable user identifier. Defaults to `sub` | + +Serve it with `Access-Control-Allow-Origin: *`. The document is public and unauthenticated, and applications validate a domain from the browser before sending the user into the flow. + +Two constraints apply to the document your `openid_configuration` URL points at, both enforced by Internet Identity: + +- The `issuer` it declares must be on the same host as the `openid_configuration` URL itself. +- Its `authorization_endpoint` must be on the same host as the `issuer`. + +Both are standard OIDC self-assertion checks. They stop a tampered discovery document from redirecting your staff to an unrelated provider. Your company domain itself may differ from the provider's host, which is what allows `acme.com` to point at `acme.okta.com`. + +That is the whole setup. Staff can now sign in with `acme.com` as their company domain. + +### Changes take up to an hour + +Internet Identity caches a resolved configuration for one hour, and keeps serving the last known good copy for a further hour if a refresh fails. Plan client or endpoint changes accordingly: publish the new file, then allow an hour before retiring the old client. + +## Step 3: Control access per application + +By default, any ICP application a user visits can be signed in to with your organization's primary client, and your provider's assignment rules for that client apply to all of them. + +To govern one application separately, give it its own OIDC client and map it in the file: + +1. Register a second OIDC client with the same settings as step 1. Copy its client ID. +2. In your provider, assign the groups or users allowed to use that client. This assignment is the access rule: assigned staff sign in normally, everyone else is stopped by your provider. +3. Add the application's origin to `app_clients`: + +```json +{ + "client_id": "0oaDEFAULT", + "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", + "name": "Acme Corp", + "app_clients": { + "https://payroll.acme.com": "0oaPAYROLL", + "https://board.acme.com": "0oaBOARD" + }, + "gate_all_apps": false, + "stable_identifier_claim": "sub" +} +``` + +Repeat for each application you want to govern separately. The map holds at most 100 entries, and a map over that limit is rejected outright rather than truncated. + +Set `gate_all_apps` to `true` to refuse any application that is not listed. Staff visiting an unlisted application then see a message telling them your organization has not granted that application access. + + + +:::note[Entra ID] +Set **Assignment required** to **Yes** on the per-application client. It defaults to **No**, which leaves the application open to your whole tenant. Entra ID also issues a tenant-stable identifier as `oid` rather than `sub`, so set `"stable_identifier_claim": "oid"`. +::: + +### Keeping application names private + +The discovery file is public, so any origin listed in `app_clients` is visible to anyone who reads it. To map an application without naming it, use a salted hash of the origin as the key instead: + +```bash +origin=https://payroll.acme.com +salt=$(openssl rand -hex 8) +hash=$(printf %s "$origin$salt" | openssl dgst -sha256 -r | cut -d' ' -f1) +echo "$hash:$salt" +``` + +Use the printed `:` value as the key: + +```json +"app_clients": { + "3f2a…c81:9f86d081884c7d65": "0oaPAYROLL" +} +``` + +Internet Identity treats any key of the form `:` as a hashed origin and matches it by recomputing `sha256(origin + salt)`. Anything else is compared as a cleartext origin, so the two forms can be mixed in one file. + +## What applications receive + +After a successful sign-in, the application receives a delegation, exactly as with any other Internet Identity sign-in. The user gets a different principal per application origin, so applications cannot correlate the same member of staff across services. + +Applications may also request identity attributes, which arrive signed by the canister and scoped to your domain, as `sso:acme.com:name` and `sso:acme.com:email`. The user is asked to consent to sharing them. + +`verified_email` is not available for SSO sign-ins. Internet Identity only marks an address as verified when it established that the user has access to it, either by verifying the address itself or through a claim scheme built in for a specific provider. It has no basis to make that claim about an address asserted by another organization's provider, so the attribute is not offered. + +## Troubleshooting + +Staff see these messages on the Internet Identity sign-in screen. Each points at a specific piece of the setup. + +| Message | Cause | +|---------|-------| +| "Couldn't load SSO settings from `acme.com`" | The discovery file is unreachable, is not valid JSON, is missing `client_id` or `openid_configuration`, or the second-hop document failed a host check. Internet Identity retries for 30 seconds before reporting this | +| "Your organization hasn't granted this app access via `acme.com`" | `gate_all_apps` is `true` and the application's origin is not in `app_clients` | +| "`acme.com`'s SSO app doesn't allow the hybrid OAuth flow" | The client from step 1 does not permit `response_type=id_token code`. Enable the implicit grant and ID tokens | +| "`acme.com`'s SSO denied the sign-in" | Your provider rejected the user, usually because they are not assigned to the client | + +To check the setup yourself, fetch both documents in the order Internet Identity does: + +```bash +curl https://acme.com/.well-known/ii-openid-configuration +curl https://acme.okta.com/.well-known/openid-configuration +``` + +The first must return your client ID and the discovery URL. The second must return an `issuer`, a `jwks_uri`, and an `authorization_endpoint`, all on the host that serves it. + +## Next steps + +- [Internet Identity](internet-identity.md): how applications integrate the sign-in flow, including sending users straight to your SSO. +- [Verifiable credentials](verifiable-credentials.md): issue signed attestations about users from a canister. + + diff --git a/docs/guides/authentication/verifiable-credentials.md b/docs/guides/authentication/verifiable-credentials.md index 235833e1..dc2c5ab1 100644 --- a/docs/guides/authentication/verifiable-credentials.md +++ b/docs/guides/authentication/verifiable-credentials.md @@ -2,7 +2,7 @@ title: "Verifiable credentials" description: "Issue and verify credentials on ICP using Internet Identity and the VC protocol: covers issuer and relying party integration patterns." sidebar: - order: 2 + order: 3 --- A verifiable credential (VC) is a cryptographically signed digital attestation about a user: for example, that they are over 18, passed KYC, or are a member of an organization. On ICP, verifiable credentials are issued by canister-based issuers, mediated by Internet Identity, and consumed by relying party applications. From f512fb78c5b6a5fa8e5765b6b545d341beee206e Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:08:45 +0200 Subject: [PATCH 02/12] docs: cut the sso guide back to the setup steps Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/single-sign-on.md | 143 ++++++------------- 1 file changed, 41 insertions(+), 102 deletions(-) diff --git a/docs/guides/authentication/single-sign-on.md b/docs/guides/authentication/single-sign-on.md index c58013c1..4d2703b6 100644 --- a/docs/guides/authentication/single-sign-on.md +++ b/docs/guides/authentication/single-sign-on.md @@ -1,97 +1,76 @@ --- title: "Single sign-on" -description: "Connect your organization's OpenID provider to Internet Identity so staff sign in to ICP applications with their company account, and control access per application." +description: "Connect your company SSO to Internet Computer applications: register an OIDC client, publish one file on your domain, and optionally gate access app by app." sidebar: order: 2 --- -Internet Identity can authenticate your staff against your own OpenID Connect provider (Okta, Entra ID, Google Workspace, Auth0, Keycloak, or any other OIDC-compliant IdP). Staff enter your company domain on the Internet Identity sign-in screen and authenticate with their existing company account. +Internet Identity can authenticate your staff against your company's OpenID Connect provider. Set up once for everyone, then control access app by app. -This guide is for the administrator of the identity provider. Two steps switch it on for the whole organization, and an optional third step controls access application by application. No registration with Internet Identity is required: it discovers your configuration from a file you publish on your domain. +This guide is for the SSO administrator. If you are building an application, see [Internet Identity](internet-identity.md). -If you are building an application and want to send users into this flow, see [Internet Identity](internet-identity.md). +1. Register an OIDC client in your IdP. +2. Publish one file on your domain. +3. Gate each app (optional). -## How it works +## Switch on SSO for the organization -1. A user picks **Continue with SSO** on the Internet Identity sign-in screen and enters your company domain, for example `acme.com`. -2. Internet Identity fetches `https://acme.com/.well-known/ii-openid-configuration` and reads the OIDC client to use. -3. It follows the `openid_configuration` URL in that file to your provider's standard OIDC discovery document, which supplies the issuer, the authorization endpoint, and the signing keys. -4. The user authenticates with your provider. Your provider returns an ID token. -5. Internet Identity verifies that token against your provider's published keys and issues the user a delegation for the application they are signing in to. +Required, one time. -Verification happens onchain, in the Internet Identity canister. Your provider's signing keys are fetched by the network, not by the user's browser, and the token never has to be trusted by the application. +### 1. Register an OIDC client -## Step 1: Register an OIDC client - -In your identity provider, create an application integration of type **OIDC / Web application**, configured as follows. +Create App Integration → **OIDC** → **Web Application**. | Setting | Value | |---------|-------| | Redirect URI | `https://id.ai/callback` | -| Grant types | Authorization code **and** implicit (the hybrid flow) | -| ID token | Allowed with the implicit grant | -| Access token | Not required. Leave it unchecked | +| Grant types | Authorization Code and Implicit (hybrid) | +| ID token | Allow ID Token with implicit grant | +| Access token | Leave Access Token unchecked | | Scopes | `openid`, `profile`, `email` | -Internet Identity uses `response_type=code id_token` with `response_mode=form_post`, and verifies the ID token in the canister. There is no token-endpoint exchange, so a client restricted to the authorization-code flow alone cannot be used. A client that does not allow an ID token with the implicit grant produces an `unsupported_response_type` error on the sign-in screen. - -Copy the client ID when you are done. You need it in step 2. +Copy down the `client_id`, for example `0oaDEFAULT`. -## Step 2: Publish the discovery file +### 2. Publish the discovery file -Serve the following document over HTTPS at exactly this path on your company domain: +Serve it over HTTPS at exactly this path: ``` https://acme.com/.well-known/ii-openid-configuration ``` -```json -{ - "client_id": "0oaDEFAULT", - "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", - "name": "Acme Corp" -} -``` - -| Field | Required | Meaning | -|-------|----------|---------| -| `client_id` | Yes | The client from step 1. Every ID token's `aud` claim must match it | -| `openid_configuration` | Yes | Your provider's OIDC discovery URL. Must be `https` | -| `name` | No | Label shown on the sign-in screen and on consent prompts. Falls back to the domain. Maximum 255 bytes | -| `app_clients` | No | Per-application access control. See step 3 | -| `gate_all_apps` | No | Deny applications not listed in `app_clients`. Defaults to `false` | -| `stable_identifier_claim` | No | Claim used as the stable user identifier. Defaults to `sub` | +- `client_id`: the client from step 1. +- `openid_configuration`: your IdP's OIDC discovery URL. +- `name`: optional label on the sign-in screen. -Serve it with `Access-Control-Allow-Origin: *`. The document is public and unauthenticated, and applications validate a domain from the browser before sending the user into the flow. +Serve it with `Access-Control-Allow-Origin: *` so applications can check the domain before sending a user into the flow. -Two constraints apply to the document your `openid_configuration` URL points at, both enforced by Internet Identity: +Done. On **id.ai** staff choose **Sign in with SSO**, enter **acme.com** as their company domain, then authenticate against your IdP. -- The `issuer` it declares must be on the same host as the `openid_configuration` URL itself. -- Its `authorization_endpoint` must be on the same host as the `issuer`. +## Control access per application -Both are standard OIDC self-assertion checks. They stop a tampered discovery document from redirecting your staff to an unrelated provider. Your company domain itself may differ from the provider's host, which is what allows `acme.com` to point at `acme.okta.com`. +Optional, repeat per app. -That is the whole setup. Staff can now sign in with `acme.com` as their company domain. +**a. Add a client for the app.** Register a second OIDC client, identical settings to step 1. Copy its `client_id`, for example `0oaPAYROLL`. -### Changes take up to an hour +**b. Assign who is allowed.** That client → **Assignments** → add the groups or users. This assignment is the access rule: assigned staff sign in as normal, anyone else is stopped by your IdP. -Internet Identity caches a resolved configuration for one hour, and keeps serving the last known good copy for a further hour if a refresh fails. Plan client or endpoint changes accordingly: publish the new file, then allow an hour before retiring the old client. +**c. Map the app to it.** Add one `app_clients` line to the file from step 2. Repeat for each app you want to gate. -## Step 3: Control access per application + -By default, any ICP application a user visits can be signed in to with your organization's primary client, and your provider's assignment rules for that client apply to all of them. - -To govern one application separately, give it its own OIDC client and map it in the file: +:::note[Entra ID] +Set **Assignment required** to **Yes**. It defaults to **No**, which opens the app to your whole tenant. +::: -1. Register a second OIDC client with the same settings as step 1. Copy its client ID. -2. In your provider, assign the groups or users allowed to use that client. This assignment is the access rule: assigned staff sign in normally, everyone else is stopped by your provider. -3. Add the application's origin to `app_clients`: +## The complete file ```json { "client_id": "0oaDEFAULT", "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", "name": "Acme Corp", + "app_clients": { "https://payroll.acme.com": "0oaPAYROLL", "https://board.acme.com": "0oaBOARD" @@ -101,68 +80,28 @@ To govern one application separately, give it its own OIDC client and map it in } ``` -Repeat for each application you want to govern separately. The map holds at most 100 entries, and a map over that limit is rejected outright rather than truncated. - -Set `gate_all_apps` to `true` to refuse any application that is not listed. Staff visiting an unlisted application then see a message telling them your organization has not granted that application access. - - - -:::note[Entra ID] -Set **Assignment required** to **Yes** on the per-application client. It defaults to **No**, which leaves the application open to your whole tenant. Entra ID also issues a tenant-stable identifier as `oid` rather than `sub`, so set `"stable_identifier_claim": "oid"`. -::: +`client_id`, `openid_configuration`, and `name` switch on SSO for the organization. The rest is per-app access control. On Entra ID, set `stable_identifier_claim` to `oid`. -### Keeping application names private +### Hiding an app name -The discovery file is public, so any origin listed in `app_clients` is visible to anyone who reads it. To map an application without naming it, use a salted hash of the origin as the key instead: +The file is public, so listed origins are visible. Run these lines with `origin` set to the app's URL. The printed value is its `app_clients` key. ```bash origin=https://payroll.acme.com salt=$(openssl rand -hex 8) -hash=$(printf %s "$origin$salt" | openssl dgst -sha256 -r | cut -d' ' -f1) +data=$origin$salt +out=$(printf %s "$data" | openssl dgst -sha256 -r) +hash=$(echo $out | cut -d' ' -f1) echo "$hash:$salt" ``` -Use the printed `:` value as the key: - -```json -"app_clients": { - "3f2a…c81:9f86d081884c7d65": "0oaPAYROLL" -} -``` - -Internet Identity treats any key of the form `:` as a hashed origin and matches it by recomputing `sha256(origin + salt)`. Anything else is compared as a cleartext origin, so the two forms can be mixed in one file. - -## What applications receive - -After a successful sign-in, the application receives a delegation, exactly as with any other Internet Identity sign-in. The user gets a different principal per application origin, so applications cannot correlate the same member of staff across services. - -Applications may also request identity attributes, which arrive signed by the canister and scoped to your domain, as `sso:acme.com:name` and `sso:acme.com:email`. The user is asked to consent to sharing them. - -`verified_email` is not available for SSO sign-ins. Internet Identity only marks an address as verified when it established that the user has access to it, either by verifying the address itself or through a claim scheme built in for a specific provider. It has no basis to make that claim about an address asserted by another organization's provider, so the attribute is not offered. - -## Troubleshooting - -Staff see these messages on the Internet Identity sign-in screen. Each points at a specific piece of the setup. - -| Message | Cause | -|---------|-------| -| "Couldn't load SSO settings from `acme.com`" | The discovery file is unreachable, is not valid JSON, is missing `client_id` or `openid_configuration`, or the second-hop document failed a host check. Internet Identity retries for 30 seconds before reporting this | -| "Your organization hasn't granted this app access via `acme.com`" | `gate_all_apps` is `true` and the application's origin is not in `app_clients` | -| "`acme.com`'s SSO app doesn't allow the hybrid OAuth flow" | The client from step 1 does not permit `response_type=id_token code`. Enable the implicit grant and ID tokens | -| "`acme.com`'s SSO denied the sign-in" | Your provider rejected the user, usually because they are not assigned to the client | - -To check the setup yourself, fetch both documents in the order Internet Identity does: - -```bash -curl https://acme.com/.well-known/ii-openid-configuration -curl https://acme.okta.com/.well-known/openid-configuration -``` +### Denying unlisted apps -The first must return your client ID and the discovery URL. The second must return an `issuer`, a `jwks_uri`, and an `authorization_endpoint`, all on the host that serves it. +`gate_all_apps: true` refuses any app not listed. ## Next steps -- [Internet Identity](internet-identity.md): how applications integrate the sign-in flow, including sending users straight to your SSO. +- [Internet Identity](internet-identity.md): how applications send users into this flow. - [Verifiable credentials](verifiable-credentials.md): issue signed attestations about users from a canister. From 96b6d3539a0ff7e1036129af239d305a6ce4a2d9 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:28:24 +0200 Subject: [PATCH 03/12] docs: restructure the sso guide around its three steps The three steps are now the top-level sections, so the page outline is the flow and the duplicate list in the intro is gone. Per-app access keeps its steps together with the gate and the hashed-key recipe, and the full file moves to the end as reference. The hashed-key section now says where to run the snippet and what to do with what it prints. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/single-sign-on.md | 104 +++++++++++-------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/docs/guides/authentication/single-sign-on.md b/docs/guides/authentication/single-sign-on.md index 4d2703b6..5b66e6d1 100644 --- a/docs/guides/authentication/single-sign-on.md +++ b/docs/guides/authentication/single-sign-on.md @@ -5,21 +5,15 @@ sidebar: order: 2 --- -Internet Identity can authenticate your staff against your company's OpenID Connect provider. Set up once for everyone, then control access app by app. +Internet Identity can authenticate your staff against your company's existing OpenID Connect provider, such as Okta, Entra ID, Google Workspace, or Auth0. Staff enter your company domain on the sign-in screen and authenticate with the account they already have. -This guide is for the SSO administrator. If you are building an application, see [Internet Identity](internet-identity.md). - -1. Register an OIDC client in your IdP. -2. Publish one file on your domain. -3. Gate each app (optional). +Setup is two steps and takes one OIDC client and one file on your domain. Nothing has to be registered with Internet Identity: it discovers your configuration from that file. A third, optional step controls access app by app. -## Switch on SSO for the organization - -Required, one time. +This guide is for the SSO administrator. If you are building an application, see [Internet Identity](internet-identity.md). -### 1. Register an OIDC client +## 1. Register an OIDC client -Create App Integration → **OIDC** → **Web Application**. +In your identity provider, create App Integration → **OIDC** → **Web Application**. | Setting | Value | |---------|-------| @@ -29,42 +23,89 @@ Create App Integration → **OIDC** → **Web Application**. | Access token | Leave Access Token unchecked | | Scopes | `openid`, `profile`, `email` | -Copy down the `client_id`, for example `0oaDEFAULT`. +Copy down the `client_id`, for example `0oaDEFAULT`. You need it in step 2. -### 2. Publish the discovery file +## 2. Publish the discovery file -Serve it over HTTPS at exactly this path: +Serve a file over HTTPS at exactly this path on your company domain: ``` https://acme.com/.well-known/ii-openid-configuration ``` -- `client_id`: the client from step 1. -- `openid_configuration`: your IdP's OIDC discovery URL. -- `name`: optional label on the sign-in screen. +```json +{ + "client_id": "0oaDEFAULT", + "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", + "name": "Acme Corp" +} +``` + +| Field | Value | +|-------|-------| +| `client_id` | The client from step 1 | +| `openid_configuration` | Your IdP's OIDC discovery URL | +| `name` | Optional label on the sign-in screen | Serve it with `Access-Control-Allow-Origin: *` so applications can check the domain before sending a user into the flow. -Done. On **id.ai** staff choose **Sign in with SSO**, enter **acme.com** as their company domain, then authenticate against your IdP. +That is the whole setup. On **id.ai**, staff choose **Sign in with SSO**, enter **acme.com** as their company domain, then authenticate against your IdP. + +## 3. Gate access per app (optional) -## Control access per application +By default your staff can sign in to any Internet Computer application with the client from step 1, and your provider's assignment rules for that client apply everywhere. To govern one application on its own, give it a client of its own. -Optional, repeat per app. +Repeat these three steps for each application you want to gate. **a. Add a client for the app.** Register a second OIDC client, identical settings to step 1. Copy its `client_id`, for example `0oaPAYROLL`. **b. Assign who is allowed.** That client → **Assignments** → add the groups or users. This assignment is the access rule: assigned staff sign in as normal, anyone else is stopped by your IdP. -**c. Map the app to it.** Add one `app_clients` line to the file from step 2. Repeat for each app you want to gate. +**c. Map the app to it.** Add one `app_clients` line to the file from step 2, keyed by the application's origin: + +```json +"app_clients": { + "https://payroll.acme.com": "0oaPAYROLL" +} +``` + +To refuse any application that is not listed, add `"gate_all_apps": true`. :::note[Entra ID] -Set **Assignment required** to **Yes**. It defaults to **No**, which opens the app to your whole tenant. +Set **Assignment required** to **Yes**. It defaults to **No**, which opens the app to your whole tenant. Entra ID also identifies users by `oid` rather than `sub`, so add `"stable_identifier_claim": "oid"` to the file. ::: +### Hiding an app name + +The file is public, so any origin you list is visible to anyone who reads it. To map an application without naming it, use a salted hash of its origin as the key instead of the origin itself. + +Run this in a shell, with `origin` set to the application's URL: + +```bash +origin=https://payroll.acme.com +salt=$(openssl rand -hex 8) +data=$origin$salt +out=$(printf %s "$data" | openssl dgst -sha256 -r) +hash=$(echo $out | cut -d' ' -f1) +echo "$hash:$salt" +``` + +It prints one value, in the form `:`. Use it as the key in place of the origin: + +```json +"app_clients": { + "9c8dbbd738e2e390267c7dd7350623c541907a66a1f064e22c13d954e08322af:9f86d081884c7d65": "0oaPAYROLL" +} +``` + +Internet Identity matches the key by hashing the origin of whichever application the user is signing in to, so cleartext and hashed keys can be mixed in one file. + ## The complete file +Every field, with the optional ones filled in: + ```json { "client_id": "0oaDEFAULT", @@ -80,25 +121,6 @@ Set **Assignment required** to **Yes**. It defaults to **No**, which opens the a } ``` -`client_id`, `openid_configuration`, and `name` switch on SSO for the organization. The rest is per-app access control. On Entra ID, set `stable_identifier_claim` to `oid`. - -### Hiding an app name - -The file is public, so listed origins are visible. Run these lines with `origin` set to the app's URL. The printed value is its `app_clients` key. - -```bash -origin=https://payroll.acme.com -salt=$(openssl rand -hex 8) -data=$origin$salt -out=$(printf %s "$data" | openssl dgst -sha256 -r) -hash=$(echo $out | cut -d' ' -f1) -echo "$hash:$salt" -``` - -### Denying unlisted apps - -`gate_all_apps: true` refuses any app not listed. - ## Next steps - [Internet Identity](internet-identity.md): how applications send users into this flow. From 1592db5edd65ff73ce7b9ea9202d426fec3403cc Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:31:18 +0200 Subject: [PATCH 04/12] docs: retitle the guide to Enterprise SSO Names the audience rather than the mechanism, so a company scanning the sidebar can see the page is about connecting their own provider. The file is renamed to match the title, and the code fence gets a language tag. Co-Authored-By: Claude Opus 5 (1M context) --- .../authentication/{single-sign-on.md => enterprise-sso.md} | 6 +++--- docs/guides/authentication/internet-identity.mdx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename docs/guides/authentication/{single-sign-on.md => enterprise-sso.md} (95%) diff --git a/docs/guides/authentication/single-sign-on.md b/docs/guides/authentication/enterprise-sso.md similarity index 95% rename from docs/guides/authentication/single-sign-on.md rename to docs/guides/authentication/enterprise-sso.md index 5b66e6d1..da6168e9 100644 --- a/docs/guides/authentication/single-sign-on.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -1,6 +1,6 @@ --- -title: "Single sign-on" -description: "Connect your company SSO to Internet Computer applications: register an OIDC client, publish one file on your domain, and optionally gate access app by app." +title: "Enterprise SSO" +description: "Connect your company's OpenID Connect provider to Internet Computer applications: register an OIDC client, publish one file on your domain, and optionally gate access app by app." sidebar: order: 2 --- @@ -29,7 +29,7 @@ Copy down the `client_id`, for example `0oaDEFAULT`. You need it in step 2. Serve a file over HTTPS at exactly this path on your company domain: -``` +```text https://acme.com/.well-known/ii-openid-configuration ``` diff --git a/docs/guides/authentication/internet-identity.mdx b/docs/guides/authentication/internet-identity.mdx index e53f0aac..bf567fb6 100644 --- a/docs/guides/authentication/internet-identity.mdx +++ b/docs/guides/authentication/internet-identity.mdx @@ -160,7 +160,7 @@ if (await isValidSsoDomain(domainInput.value, controller.signal)) { Call `controller.abort()` when the input changes. An aborted check rejects instead of returning `false`, so a superseded check is never read as an invalid domain. The check also never resolves in under 750 ms, which keeps a partially typed domain from flashing an error on every keystroke. -For what an organization publishes to make this flow work, see [Single sign-on](single-sign-on.md). +For what an organization publishes to make this flow work, see [Enterprise SSO](enterprise-sso.md). ### Create an authenticated agent @@ -663,7 +663,7 @@ For full details, see the [Internet Identity specification](../../references/int ## Next steps -- [Single sign-on](single-sign-on.md) for connecting an organization's own OpenID provider, from the administrator's side +- [Enterprise SSO](enterprise-sso.md) for connecting an organization's own OpenID provider, from the administrator's side - [Wallet integration](../digital-assets/wallet-integration.md) for token-based authentication alternatives - [Frontend frameworks](../frontends/frameworks.md) for framework-specific auth setup patterns - [Internet Identity specification](../../references/internet-identity-spec.md) for protocol details and the full alternative origins spec From 40d734d158c548178093ea19b43505f127c9aa0f Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:33:16 +0200 Subject: [PATCH 05/12] docs: leave verifiable credentials out of the sso guide Drops the Next steps link to it and restores its sidebar order, so the page is untouched by this branch. Enterprise SSO still sorts ahead of it within the Authentication group. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 2 +- docs/guides/authentication/verifiable-credentials.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index da6168e9..dbe85707 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -124,6 +124,6 @@ Every field, with the optional ones filled in: ## Next steps - [Internet Identity](internet-identity.md): how applications send users into this flow. -- [Verifiable credentials](verifiable-credentials.md): issue signed attestations about users from a canister. +- [`@icp-sdk/auth` reference](https://js.icp.build): the client library applications use to start it. diff --git a/docs/guides/authentication/verifiable-credentials.md b/docs/guides/authentication/verifiable-credentials.md index dc2c5ab1..235833e1 100644 --- a/docs/guides/authentication/verifiable-credentials.md +++ b/docs/guides/authentication/verifiable-credentials.md @@ -2,7 +2,7 @@ title: "Verifiable credentials" description: "Issue and verify credentials on ICP using Internet Identity and the VC protocol: covers issuer and relying party integration patterns." sidebar: - order: 3 + order: 2 --- A verifiable credential (VC) is a cryptographically signed digital attestation about a user: for example, that they are over 18, passed KYC, or are a member of an organization. On ICP, verifiable credentials are issued by canister-based issuers, mediated by Internet Identity, and consumed by relying party applications. From 78f708341d1186523e77855703da14f82a590327 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:58:21 +0200 Subject: [PATCH 06/12] docs: explain stable_identifier_claim where it applies It appeared only in the Entra note and then unannounced in the complete file. It exists because a per-app client can change the sub a provider issues for the same person, so it is introduced in the per-app step, and the complete file now has a table for the fields that step adds. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index dbe85707..5ef065d9 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -71,6 +71,8 @@ Repeat these three steps for each application you want to gate. To refuse any application that is not listed, add `"gate_all_apps": true`. +Some providers issue a different `sub` for the same person in each OIDC client. Where that is the case, sign-ins through a per-app client would look like a different person, so name a claim that stays stable across your clients with `"stable_identifier_claim"`. It defaults to `sub`, which is correct when your provider's `sub` is already the same in every client. + :::note[Entra ID] @@ -104,7 +106,7 @@ Internet Identity matches the key by hashing the origin of whichever application ## The complete file -Every field, with the optional ones filled in: +Every field, with the optional ones from step 3 filled in: ```json { @@ -121,6 +123,14 @@ Every field, with the optional ones filled in: } ``` +The first three fields switch on SSO for the organization. The rest control access per app: + +| Field | Default | Purpose | +|-------|---------|---------| +| `app_clients` | none | Maps an application's origin, or a salted hash of it, to the client that governs it | +| `gate_all_apps` | `false` | Refuse applications that are not listed in `app_clients` | +| `stable_identifier_claim` | `sub` | The claim that identifies the same person across your clients | + ## Next steps - [Internet Identity](internet-identity.md): how applications send users into this flow. From 51006e1fe50f1871d7e7dfe86eff32925905c796 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 16:59:32 +0200 Subject: [PATCH 07/12] docs: give the per-app gate and the subject claim their own sections Both were trailing sentences in step 3, so the default-deny switch read as a footnote and the subject claim did not state its precondition. Each is now a subsection: what happens to unlisted apps and which default to pick, and the pairwise-sub case that only arises once an app has its own client. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index 5ef065d9..7a0159ec 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -69,16 +69,26 @@ Repeat these three steps for each application you want to gate. } ``` -To refuse any application that is not listed, add `"gate_all_apps": true`. - -Some providers issue a different `sub` for the same person in each OIDC client. Where that is the case, sign-ins through a per-app client would look like a different person, so name a claim that stays stable across your clients with `"stable_identifier_claim"`. It defaults to `sub`, which is correct when your provider's `sub` is already the same in every client. - :::note[Entra ID] -Set **Assignment required** to **Yes**. It defaults to **No**, which opens the app to your whole tenant. Entra ID also identifies users by `oid` rather than `sub`, so add `"stable_identifier_claim": "oid"` to the file. +Set **Assignment required** to **Yes** on the per-app client. It defaults to **No**, which opens the app to your whole tenant. ::: +### Applications you have not listed + +By default, an application missing from `app_clients` falls back to the organization's client from step 1, so staff can sign in to it like any other. Set `"gate_all_apps": true` to refuse those sign-ins instead, and staff visiting an unlisted application are told your organization has not granted it access. + +Use `true` when the list is meant to be exhaustive, so a new application cannot be signed in to until you have added it deliberately. + +### Providers that issue a per-client subject + +This applies only once an application has a client of its own. + +Some providers, Entra ID among them, issue a different `sub` for the same person in each OIDC client. Sign-ins through the per-app client would then look like a different person from sign-ins through the organization's client. Set `"stable_identifier_claim"` to a claim that stays the same across your clients: on Entra ID that is `oid`. + +It defaults to `sub`, which is correct when your provider's `sub` is already the same in every client. + ### Hiding an app name The file is public, so any origin you list is visible to anyone who reads it. To map an application without naming it, use a salted hash of its origin as the key instead of the origin itself. From 9d18a8338070e4d12a251984652c614792322d1b Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 17:00:33 +0200 Subject: [PATCH 08/12] docs: put the entra caveats in the steps they affect Both sat in one aside, where a reader skimming the steps would miss them. Assignment required now sits in the assignment step it modifies, since missing it leaves an app open to the whole tenant, and the oid claim sits with the subject-claim section. No aside remains. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index 7a0159ec..ca877172 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -57,9 +57,11 @@ By default your staff can sign in to any Internet Computer application with the Repeat these three steps for each application you want to gate. + + **a. Add a client for the app.** Register a second OIDC client, identical settings to step 1. Copy its `client_id`, for example `0oaPAYROLL`. -**b. Assign who is allowed.** That client → **Assignments** → add the groups or users. This assignment is the access rule: assigned staff sign in as normal, anyone else is stopped by your IdP. +**b. Assign who is allowed.** That client → **Assignments** → add the groups or users. This assignment is the access rule: assigned staff sign in as normal, anyone else is stopped by your IdP. On Entra ID, set **Assignment required** to **Yes** on the client as well. It defaults to **No**, which leaves the app open to your whole tenant. **c. Map the app to it.** Add one `app_clients` line to the file from step 2, keyed by the application's origin: @@ -69,12 +71,6 @@ Repeat these three steps for each application you want to gate. } ``` - - -:::note[Entra ID] -Set **Assignment required** to **Yes** on the per-app client. It defaults to **No**, which opens the app to your whole tenant. -::: - ### Applications you have not listed By default, an application missing from `app_clients` falls back to the organization's client from step 1, so staff can sign in to it like any other. Set `"gate_all_apps": true` to refuse those sign-ins instead, and staff visiting an unlisted application are told your organization has not granted it access. From 2a0567bed348c36ee3774f6923636fce875dfc65 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 17:03:48 +0200 Subject: [PATCH 09/12] docs: document session_max_age_seconds for the sso discovery file Gives admins a way to say how long a sign-in stays valid before staff authenticate again. Named after the OIDC max_age parameter, in seconds, and documented as a cap on whatever lifetime an application asks for. The field is pending implementation in Internet Identity: the section carries a comment saying so, and it must not be published before the canister supports it. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 28 +++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index ca877172..aed0dbb2 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -51,6 +51,24 @@ Serve it with `Access-Control-Allow-Origin: *` so applications can check the dom That is the whole setup. On **id.ai**, staff choose **Sign in with SSO**, enter **acme.com** as their company domain, then authenticate against your IdP. +### How long a sign-in lasts + + + +Add `"session_max_age_seconds"` to cap how long a sign-in stays valid. Once that much time has passed since a member of staff authenticated, they authenticate against your IdP again: + +```json +{ + "client_id": "0oaDEFAULT", + "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", + "session_max_age_seconds": 28800 +} +``` + +Eight hours (`28800`) covers a working day, so staff re-authenticate at most daily. The ceiling is 30 days (`2592000`). + +Applications choose their own session length as well, and this value caps it: an application asking for 30 days on a domain that allows eight hours gets eight hours. Leave the field out and the application's own choice applies. + ## 3. Gate access per app (optional) By default your staff can sign in to any Internet Computer application with the client from step 1, and your provider's assignment rules for that client apply everywhere. To govern one application on its own, give it a client of its own. @@ -120,6 +138,12 @@ Every field, with the optional ones from step 3 filled in: "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", "name": "Acme Corp", + "app_clients": { + "https://payroll.acme.com": "0oaPAYROLL", + "https://board.acme.com": "0oaBOARD" + }, + "session_max_age_seconds": 28800, + "app_clients": { "https://payroll.acme.com": "0oaPAYROLL", "https://board.acme.com": "0oaBOARD" @@ -129,10 +153,12 @@ Every field, with the optional ones from step 3 filled in: } ``` -The first three fields switch on SSO for the organization. The rest control access per app: +`client_id` and `openid_configuration` are required. The rest are optional: | Field | Default | Purpose | |-------|---------|---------| +| `name` | the domain | Label shown on the sign-in screen | +| `session_max_age_seconds` | unset | How long a sign-in stays valid before staff authenticate again | | `app_clients` | none | Maps an application's origin, or a salted hash of it, to the client that governs it | | `gate_all_apps` | `false` | Refuse applications that are not listed in `app_clients` | | `stable_identifier_claim` | `sub` | The claim that identifies the same person across your clients | From 6ce94c7ce08fb0a98869e5e629c5473492c4ae1b Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 17:06:18 +0200 Subject: [PATCH 10/12] docs: drop the pending-implementation marker Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index aed0dbb2..194a83fa 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -53,8 +53,6 @@ That is the whole setup. On **id.ai**, staff choose **Sign in with SSO**, enter ### How long a sign-in lasts - - Add `"session_max_age_seconds"` to cap how long a sign-in stays valid. Once that much time has passed since a member of staff authenticated, they authenticate against your IdP again: ```json From c11c7204453d59b7a0ef88eaa4bde875995716f6 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 17:39:22 +0200 Subject: [PATCH 11/12] docs: fix the duplicated app_clients in the complete file The block appeared twice, split by a blank line, and the lead-in still referred to step 3 after the session field was added in step 2. One block now, in field order, with no blank lines inside it. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index 194a83fa..2f94a18d 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -128,20 +128,14 @@ Internet Identity matches the key by hashing the origin of whichever application ## The complete file -Every field, with the optional ones from step 3 filled in: +Every field, with the optional ones filled in: ```json { "client_id": "0oaDEFAULT", "openid_configuration": "https://acme.okta.com/.well-known/openid-configuration", "name": "Acme Corp", - - "app_clients": { - "https://payroll.acme.com": "0oaPAYROLL", - "https://board.acme.com": "0oaBOARD" - }, "session_max_age_seconds": 28800, - "app_clients": { "https://payroll.acme.com": "0oaPAYROLL", "https://board.acme.com": "0oaBOARD" From 03f84bfd1865d5ff3491bdaa65c3d462efed8488 Mon Sep 17 00:00:00 2001 From: sea-snake Date: Tue, 4 Aug 2026 17:40:25 +0200 Subject: [PATCH 12/12] docs: state the eight-hour default for session_max_age_seconds The field defaults to 28800 rather than being unset, so leaving it out caps a sign-in at eight hours instead of deferring to whatever the application asks for. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/authentication/enterprise-sso.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/guides/authentication/enterprise-sso.md b/docs/guides/authentication/enterprise-sso.md index 2f94a18d..23d2fc9e 100644 --- a/docs/guides/authentication/enterprise-sso.md +++ b/docs/guides/authentication/enterprise-sso.md @@ -53,7 +53,7 @@ That is the whole setup. On **id.ai**, staff choose **Sign in with SSO**, enter ### How long a sign-in lasts -Add `"session_max_age_seconds"` to cap how long a sign-in stays valid. Once that much time has passed since a member of staff authenticated, they authenticate against your IdP again: +A sign-in stays valid for eight hours. Once that much time has passed since a member of staff authenticated, they authenticate against your IdP again. Set `"session_max_age_seconds"` to choose a different length: ```json { @@ -63,9 +63,9 @@ Add `"session_max_age_seconds"` to cap how long a sign-in stays valid. Once that } ``` -Eight hours (`28800`) covers a working day, so staff re-authenticate at most daily. The ceiling is 30 days (`2592000`). +The default of eight hours (`28800`) covers a working day, so staff re-authenticate at most daily. The ceiling is 30 days (`2592000`). -Applications choose their own session length as well, and this value caps it: an application asking for 30 days on a domain that allows eight hours gets eight hours. Leave the field out and the application's own choice applies. +Applications choose their own session length as well, and this value caps it: an application asking for 30 days on a domain that allows eight hours gets eight hours. ## 3. Gate access per app (optional) @@ -150,7 +150,7 @@ Every field, with the optional ones filled in: | Field | Default | Purpose | |-------|---------|---------| | `name` | the domain | Label shown on the sign-in screen | -| `session_max_age_seconds` | unset | How long a sign-in stays valid before staff authenticate again | +| `session_max_age_seconds` | `28800` (eight hours) | How long a sign-in stays valid before staff authenticate again | | `app_clients` | none | Maps an application's origin, or a salted hash of it, to the client that governs it | | `gate_all_apps` | `false` | Refuse applications that are not listed in `app_clients` | | `stable_identifier_claim` | `sub` | The claim that identifies the same person across your clients |