For AI agents: Documentation index at /llms.txt

Skip to content

One-click sign-in

By default, signIn() opens Internet Identity and the user picks how to authenticate. One-click sign-in skips that choice: the user lands directly on the provider’s own screen. Internet Identity is still the signer: it verifies the provider’s token and issues the delegation.

A client is built for one of two entry points, never both:

OptionSends the user toValue
openIdProviderA provider Internet Identity has built in"google", "apple", or "microsoft"
ssoDomainAn organization’s own OpenID providerThe organization’s domain, such as "acme.com"

Both are constructor options, fixed for the client’s lifetime. To offer several, build one client per choice.

import { AuthClient } from "@icp-sdk/auth/client";
const authClient = new AuthClient({ openIdProvider: "google" });
await authClient.signIn();

The user goes straight to Google’s account chooser. The rest of the flow (getStatus(), getIdentity(), signOut()) is unchanged.

const authClient = new AuthClient({ ssoDomain: "acme.com" });
await authClient.signIn();

Internet Identity reads the organization’s configuration from https://acme.com/.well-known/ii-openid-configuration and sends the user to the provider named there. Any organization that publishes that file can be signed in against, with nothing registered ahead of time.

The domain is normalized when the client is built: lowercased, IDNA-encoded, and reduced to a host with an optional port. A value carrying a scheme, a path, a query, or a fragment is not a domain, and the client reports it as invalid (see below).

If your app sets a derivationOrigin, the client sends it along with the domain, so Internet Identity uses the client the organization assigned to that origin.

An app that asks the user for their organization’s domain can show whether it works before they continue. A client built with ssoDomain checks its domain against Internet Identity by itself, and getSsoStatus() returns the result, the same way getStatus() returns the session:

StateMeaningShow
checkingInternet Identity is resolving the domain.A spinner.
availableThe domain is ready for sign-in. name is the organization’s display name, when it publishes one.“Continue with Acme Corp”.
invalidThe input is not a domain.Ask the user to correct it.
unavailableThe domain publishes no usable configuration, or resolving it failed. retryAfter is when a retry can succeed, when known.The failure, and a retry button.

getSsoStatus() is synchronous and never throws, and subscribe() calls back whenever it changes. Build a new client once the user pauses typing, and dispose of the one it replaces, which also stops its check:

let client;
let timer;
input.addEventListener("input", () => {
// Drop the old domain at once, so Continue never signs in to it.
client?.dispose();
client = undefined;
showSpinner();
clearTimeout(timer);
timer = setTimeout(() => {
const next = new AuthClient({ ssoDomain: input.value });
next.subscribe(() => render(next.getSsoStatus()));
render(next.getSsoStatus());
client = next;
}, 300);
});
function render(sso) {
switch (sso.state) {
case "checking":
return showSpinner();
case "available":
return enableContinue(sso.name);
case "invalid":
return showNotADomain();
case "unavailable":
return showUnavailable(sso.retryAfter);
}
}
// Call signIn() before any await, or the browser blocks the popup.
continueButton.addEventListener("click", () => {
client?.signIn().then(showApp, showSignInError);
});

A replaced client is disposed before it can report, so a stale result never renders. The debounce builds one client per pause rather than one per keystroke.

For a “Try again” button, call refreshSsoStatus(). While retryAfter is in the future, keep the button disabled and count down to it (“Try again in 2 min”): Internet Identity does not retry a failing domain sooner, and an early retry answers unavailable again at once.

The check also prepares Internet Identity for this domain, so signIn() on the same client starts without waiting. signIn() opens Internet Identity in every state except invalid, which rejects without opening anything. A sign-in through an unavailable domain shows Internet Identity’s own error screen. In every state, signIn() also rejects when the user closes Internet Identity or authentication fails, so handle the rejection.

A sign-in that goes to one provider can request attributes scoped to that provider, which the user grants on the same screen. See Identity attributes.