Integration guide
Add “Sign in with Tutu” to your product in four steps, using OAuth2 + PKCE.
Four steps to integrate
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.
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.
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.
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.
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.
Want to see it in action first?