TutuId

Integration guide

Add “Sign in with Tutu” to your product in four steps, using OAuth2 + PKCE.

Four steps to integrate

1

Frontend starts login

Create an instance with createTutuId({ baseUrl, clientId }) from @tutu/id-sdk, and call idSdk.startLogin() on click. The SDK generates a PKCE pair and redirects to the TutuId authorization page.

2

User authorizes on TutuId

On the /oauth/authorize consent screen the user clicks “Allow” (skipped automatically if already authorized). After TutuId checks client_id and the redirect_uri allowlist, it redirects back to your /auth/callback with an authorization code.

3

Callback page gets the code

On /auth/callback, call idSdk.completeCallback() to get { code, codeVerifier }. Hand these two values to your own backend — never exchange the token directly in the browser.

4

Backend exchanges token → creates account

Your backend exchanges code + codeVerifier for an access_token, calls /userinfo to get { sub, email, emailVerified, ... }, maps or creates a local account by sub, then issues your own session.

★ Account-takeover defense (must follow)

Your backend may only link or create a local account by sub (the unique account ID). Only when emailVerified === true may you link an existing local account by email; otherwise create a separate account and leave the email empty.

Why: an attacker could pre-register a Tutu account with a victim’s email — merging by an unverified email would hand over the victim’s local account. This is a CVE-level red line.

★ Branch your sign-out: for locally registered accounts (not linked to Tutu ID), do NOT call logoutEverywhere() — it would end the unrelated central Tutu ID session in the browser and sign the user out of the entire suite. They only wanted to leave your product. Cascade only when the account is actually linked.

SDK API reference

@tutu/id-sdk · pure client-side, zero dependencies (requires Web Crypto + sessionStorage).

createTutuId({ baseUrl, clientId, redirectUri? })

Create an SDK instance. redirectUri defaults to ${location.origin}/auth/callback, adapting to dev/prod.

startLogin(scope?)

Generates a PKCE pair and redirects to the authorization page, starting “Sign in with Tutu”.

trySilentLogin(scope?)

Silent login: if there’s a central session and prior authorization, it exchanges a code seamlessly; otherwise it falls back to signed-out immediately (without interrupting the user).

completeCallback()

Parses the result on the callback page: on success returns { code, codeVerifier }, on failure/cancel returns { error }.

logoutEverywhere(returnTo?)

Logs out the central session, cascading sign-out across every product in the suite, then returns to returnTo.