Let your visitors sign in with Face ID. A WhatsApp code the first time, a glance every time after. No passwords to forget, and none for you to keep.
One script tag on any site, a plugin for WordPress, a package for Next.js.
Look. You’re in.
Sign in on the right to finish this sentence.Sign in below to finish this sentence.
Try it · type any number · nothing is sent
Tap the message to fill the code
Sign in to Loma Coffee
lomacoffee.example
Sign in
New here? Enter your number
You’ll stay signed in on this device for 30 days
Secured by Okia
Somewhere new.Still you.
Set up once, on any site that uses Okia. On every other one, the sheet says “Welcome back” and one glance signs you in. Okia keeps you signed in on that device for 30 days, and tells you so in plain words, not a checkbox.
What each site receives
Same person. Two IDs. Nothing that links them.
We’ll assume you met Loma Coffee above.
Sign in to Vela
vela.example
Welcome back
You’ll stay signed in on this device for 30 days
Secured by Okia
Sign in to Loma Coffee
lomacoffee.example
Sign in
New here? Enter your number
You’ll stay signed in on this device for 30 days
Secured by Okia
Sign in to Loma Coffee
lomacoffee.example
Enter the code we sent to +9725•••••42
That code didn’t match
Resend code in 0:30
You’ll stay signed in on this device for 30 days
Secured by Okia
Sign in to Loma Coffee
lomacoffee.example
Sign in with Face ID next time
One look. No codes.
Secured by Okia
Sign in to Loma Coffee
lomacoffee.example
Check your device
Secured by Okia
Sign in to Loma Coffee
lomacoffee.example
You’re signed in
Secured by Okia
Sign in to Vela
vela.example
Welcome back
You’ll stay signed in on this device for 30 days
Secured by Okia
Borrowed laptop, or Face ID switched off? A WhatsApp code is one tap away.
It opens on your site.It wears your name.
Add one button. Your visitors get a sign-in sheet with your name and your verified domain at the top, so they can see exactly where they’re signing in. A popup on a computer, a full page on a phone.
Make it yours
Set your logo and colour in the dashboard, with a live preview. The sheet won’t wear a colour people can’t read. “Secured by Okia” stays at the bottom, on every site.
New this week
Fresh roast, Tuesday and Friday
Sign in to Loma Coffee
lomacoffee.example
Welcome back
You’ll stay signed in on this device for 30 days
Secured by Okia
- Your name
- Your verified domain
- Secured by Okia, always
- The one button you add
A different IDat every door.
Every site gets its own ID for the same person, pw_ and a hash made for that site alone. No two sites can match their IDs, not even two run by the same company. And Okia offers no way to look someone up across sites.
lomacoffee.example receives
pw_3vQk9XbTq2LmRzAe7sWcJ1oYhN5uGfKd0pVxEiB4rMt
An illustration. This page invents a secret when it loads and forgets it when you leave, so these IDs change on reload. Real IDs come from a secret for each site that never leaves Okia.
Phone numbers stay private too. A site sees one only if it asks, is live on a verified domain, and the person taps “Continue” rather than “Continue without sharing”.
New phone?Not locked out.
Every screen that asks your visitors for Face ID also offers a WhatsApp code. On a new phone, a code gets them in and they can turn Face ID back on. A code never erases Face ID, and anyone who skips it can stay on codes. Okia sends every code from its own WhatsApp number, so there’s nothing for you to set up. No SMS, no email.
Sign in to Loma Coffee
lomacoffee.example
this device was cancelled
Try again, or get a code on WhatsApp instead
Secured by Okia
Choose “Use a WhatsApp code instead”
Tap the message to fill the code
- 01
Half a key opens nothing.
Okia keeps only the public half of each Face ID key, and that half can’t sign anyone in. The private half stays with the person. Okia never sees it.
- 02
Look-alikes get nothing.
Face ID only answers to the real Okia sign-in at auth.okia.io. A copycat can copy the page, but not the glance.
Illustration of what the device does
Pick an address, then tap the key.
- 03
Replayed tokens get caught.
Refresh tokens change every time they’re used. Replay an old one and Okia revokes the whole chain.
- 04
Old numbers start fresh.
Phone numbers get recycled. When an account has been inactive for 180 days or more, a sign-in with its number starts a brand-new identity and the old one is quarantined. Nobody inherits a stranger’s account.
One script tag.One POST.
Paste one script tag and place <okia-button> where you want it. Your server trades a short-lived code for signed tokens in one call, in any language. It’s standard OAuth2 with PKCE, so off-the-shelf OAuth clients work unmodified.
- POST /oauth/token
- One endpoint, any language.
- ES256 JWTs
- Verified against a public JWKS. Keys rotate on their own.
- pw_ IDs
- A different subject on every site.
- 60 seconds
- How long an auth code lives. It works once.
- S256 only
- PKCE on every client, secret or not.
On the wire
One sign-in, five stops. Four of them are yours.
- 01
Your page
Your visitor taps
<okia-button>.v1.js is under 15 KB gzipped, with no dependencies. The button reads “Sign in”, then switches to “Sign in with Face ID” or “Sign in with fingerprint” once the browser confirms the device supports it. Restyle its colours, radius and size; the focus ring always stays. A tap callspw.login(), which makes a PKCE verifier and opens the sheet. - 02
The Okia sheetauth.okia.io
Sign in to Your Shop
yourshop.example
Welcome back
You’ll stay signed in on this device for 30 days
Secured by Okia
A glance, or a WhatsApp code the first time.
GET /authorizewithresponse_type=code, yourclient_idandredirect_uri, astateand an S256code_challenge. It opens as a popup on desktop, and as a full redirect on mobile or whenever a popup is blocked. Your server isn’t involved yet. - 03
Your redirect URI
yoursite.com/account?code=a1·····&state=…
Single use · 60 seconds
The browser comes back with
?code=…&state=…The code is opaque, single-use and expires in 60 seconds. The SDK checksstate, then posts the code, its verifier and the redirect URI to your exchange URL, which must be same-origin. A failed exchange burns the code, so retry from/authorize. - 04
Your server
POST /oauth/token grant_type=authorization_code code=…&code_verifier=…200 { "id_token": "eyJ…", "expires_in": 900 }One POST to
/oauth/tokentrades the code for tokens.POST /oauth/token grant_type=authorization_code&code=…&redirect_uri=…&code_verifier=… → { "token_type": "Bearer", "expires_in": 900, "access_token": "eyJ…", "id_token": "eyJ…", "refresh_token": "…", "scope": "openid profile" }Authenticate with HTTP Basic (preferred) orclient_secret. PKCE is required even with a secret. The field names are standard, so off-the-shelf OAuth clients work unmodified. No server? A public client can make this call from the browser, and gets no refresh token. - 05
Your session
- iss
- auth.okia.io
- sub
- pw_Zr8xQm2a…
- amr
- ["webauthn"]
- token_use
- "id"
Signature checked against the JWKS
Verify the ID token, then start your own session.
Check the ES256 signature against/.well-known/jwks.json, theniss,aud(your client_id),expandtoken_use“id”. An access token is signed by the same key, sotoken_useis what stops it passing as proof of who this is. Cache the JWKS bykid; keys rotate on their own. From here, the session is yours.
Inspect
Pick your stack.
<script src="https://auth.okia.io/js/v1.js" data-client-id="pw_c_YOUR_CLIENT_ID" data-redirect-uri="https://yoursite.com/account" data-exchange-url="/auth/okia/exchange" defer></script><!-- Put this element where the button should appear --><okia-button></okia-button>// POST /auth/okia/exchange — the SDK sends { code, state, code_verifier, redirect_uri }const tokenRes = await fetch(`${AUTH_ORIGIN}/oauth/token`, { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded", authorization: basic }, body: new URLSearchParams({ grant_type: "authorization_code", code: body.code, redirect_uri: body.redirect_uri, code_verifier: body.code_verifier, }),});const tokens = await tokenRes.json();({ payload: claims } = await jwtVerify(tokens.id_token, JWKS, { issuer: AUTH_ORIGIN, audience: CLIENT_ID, algorithms: ["ES256"],}));if (claims.token_use !== "id") return res.status(401).json({ error: "invalid_token" });req.session.sub = claims.sub;The dashboard prints this tag with your client ID and page filled in. The whole quickstart
wp plugin install https://app.okia.io/downloads/okia-login.zip --activate- No WP-CLI? In WP admin, Plugins → Add New → Upload Plugin, then activate.
- Settings → Okia Login → Connect to Okia, and approve in your dashboard.
- Back in WordPress, the client ID and secret are saved. Nothing to copy.
- Pure redirect with no JavaScript, so caching plugins can’t get in the way.
Plugin “Okia Login” 1.4.0. WordPress guide
npm install @okia/react// app/api/okia/[action]/route.tsimport { createOkiaHandlers } from "@okia/react/next"; export const { GET, POST } = createOkiaHandlers({ clientId: process.env.OKIA_CLIENT_ID!, clientSecret: process.env.OKIA_CLIENT_SECRET!,});// app/account.tsx"use client";import { LoginButton, useOkia } from "@okia/react"; export function Account() { const { user, logout } = useOkia(); if (!user) return <LoginButton />; return <button onClick={logout}>Sign out ({user.sub})</button>;}Pick Next.js when you create the site and the dashboard registers the callback for you. Next.js guide
The standard OAuth2 authorization code flow with PKCE (S256). Endpoints are listed at /.well-known/openid-configuration, and tokens are ES256 JWTs you verify against the public JWKS.
- GET/authorize
- POST/oauth/token
- POST/oauth/revoke
- GET/userinfo
- GET/logout
- GET/.well-known/jwks.json
- GET/.well-known/openid-configuration
Know how they signed in.
Example ID token (excerpt)
{ "sub": "pw_3vQk9XbT…", "amr": }A passkey. Phishing-resistant, and the person was verified on their device.
Tap the value for the other answer.
Test mode first. Live on its own. Test mode
Sign in to Your Shop
yourshop.example
Until your domain is verified, the sheet shows this banner, signs in up to 25 people and can’t share phone numbers.
- Add a TXT record at
_okia.<domain>, or put a file at/.well-known/okia-verify.txt. - Okia keeps checking and flips your site live on its own. On WordPress, the plugin serves the file for you.
Leave it in place. Okia re-checks every week.
Sites, branding, end users, team, signed webhooks and API keys live at app.okia.io. You sign in to it with Okia. Docs for every stack →
Your visitors areone glance away.
You sign up the way your visitors will, with your phone and a WhatsApp code. Add your first site and start testing straight away.