Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/guides/authentication/internet-identity.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
107 changes: 107 additions & 0 deletions docs/guides/authentication/single-sign-on.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
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."
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.

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).

## Switch on SSO for the organization

Required, one time.

### 1. Register an OIDC client

Create App Integration → **OIDC** → **Web Application**.

| Setting | Value |
|---------|-------|
| Redirect URI | `https://id.ai/callback` |
| 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` |

Copy down the `client_id`, for example `0oaDEFAULT`.

### 2. Publish the discovery file

Serve it over HTTPS at exactly this path:

```
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.

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.

## Control access per application

Optional, repeat per app.

**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.

<!-- Needs human verification: identity-provider-specific settings are not verifiable from ICP sources -->

:::note[Entra ID]
Set **Assignment required** to **Yes**. It defaults to **No**, which opens the app to your whole tenant.
:::

## 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"
},
"gate_all_apps": false,
"stable_identifier_claim": "sub"
}
```

`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.
- [Verifiable credentials](verifiable-credentials.md): issue signed attestations about users from a canister.

<!-- Upstream: informed by internet-identity src/internet_identity/src/openid/sso.rs -->
2 changes: 1 addition & 1 deletion docs/guides/authentication/verifiable-credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading