Concepts

How Okia login works, and the ideas you need before integrating.

The login model

Okia replaces passwords with two factors, in order of preference:

Method What the user sees When
Passkey Face ID / Touch ID / Android biometric prompt Every login after enrollment. Target: < 5s, zero typing
WhatsApp code 6-digit code delivered to their WhatsApp First-time enrollment, and always available as fallback

All login happens on Okia's hosted pages at auth.okia.io — via popup on desktop or full redirect on mobile (the SDK auto-selects; redirect is the documented baseline). Your site never sees a phone number unless the user consents to the phone scope. There is no cross-origin iframe mode.

First login (enrollment)

  1. User clicks your login button → hosted sheet opens.
  2. Enters phone number → receives a 6-digit code on WhatsApp → verifies.
  3. Offered a passkey ("Sign in with Face ID next time"). Skippable — an OTP-only account still works.
  4. Redirected back to your site with an authorization code; your backend exchanges it for tokens.

Returning login

The user taps the phone field and their passkey appears (WebAuthn conditional UI) — one biometric confirmation, no form. If they have an active Okia session under 24h old, it's a one-tap "Continue as +9•••42".

Fallback

The WhatsApp code path is always one tap away. A fallback login sets amr: ["otp"] in the ID token (see step-up below) and fires a user.otp_fallback webhook. Passkeys are never deleted by an OTP login.

Pairwise subject IDs

The same person has a different sub on every site. This is deliberate.

  • A user enrolls once into a global vault keyed by phone number.
  • Each site receives sub = "pw_" + base64url(HMAC-SHA256(site.pairwiseSalt, endUser.id)) — derived from a per-site random salt.
  • Two sites — even two sites in the same organization — cannot correlate their users, and Okia provides no API to resolve a sub across sites. Lookup is scoped to /v1/sites/{siteId}/users/{sub} only.

Consequences for you:

Do Don't
Store sub as the stable user key for your site Expect the same sub on your other sites
Request the phone scope if you genuinely need the number (double opt-in, per-site consent) Try to join users across sites by phone or sub

Note: end users have no email in Okia. There is no email scope or claim.

Sessions: yours vs Okia's

Two independent sessions exist after login:

Session Where Lifetime Controlled by
Your site's session Your cookie/backend, minted after the token exchange Whatever you choose You
Okia SSO session __Host-pw_sess cookie on auth.okia.io 30 days, rolling Okia

The SSO session is what makes login on a second connected site instant. Logging out of your site does not end the SSO session; GET /logout on the auth domain does. After a global logout, sites validating JWTs locally may accept an already-issued access token for up to 15 minutes (the access-token lifetime) — that lapse is by design and documented, not a bug.

"Remember this device" on the hosted sheet is the 30-day SSO session — disclosed to the user, not a checkbox.

The amr claim and step-up

Every ID token carries amr (authentication methods reference):

amr Meaning
["webauthn"] Passkey login — phishing-resistant, user-verified
["otp"] WhatsApp-code login — possession of the phone only

If an action on your site is sensitive (payments, changing account details), check amr. When it's ["otp"], send the user back through /authorize and require a passkey before proceeding. auth_time tells you how fresh the authentication is if you need recency, not just method.

Account safety rules worth knowing

  • Passkeys are never wiped by an OTP login, and for 24h after an OTP fallback login no passkey can be deleted at all.
  • If a phone number is recycled to a new owner (account inactive ≥ 180 days), the old account is quarantined — the new owner gets a fresh identity, and the old owner can recover via their passkey. Your site sees a new sub, never a silently transferred one.
Concepts · Okia docs