@kiauth/web-sdk
v1.1.0
Published
Kiauth Web SDK — verified-human signup, passwordless login, and cross-app session management
Readme
@kiauth/web-sdk
Three things, for any website (React, Vue, Angular, Svelte, or plain HTML):
- Verified Human — know the person signing up is a real, unique, Aadhaar-verified human. Not a bot, not a duplicate account.
- Signup / Login — passwordless "Login with Kiauth". The user approves on their phone with a biometric. No password database.
- Session management + cross-app knowledge — the user sees every app they are signed into and can revoke any of them; your server is told when they do. You can also surface logins that never went through Kiauth at all.
Backend:
https://api.kiauth.com— pass it asbaseUrl.
Install
Option A — script tag (no build tooling):
<script src="https://unpkg.com/@kiauth/[email protected]/dist/kiauth-sdk.min.js"></script>
<script>
const kiauth = new KiauthSDK({
clientId: 'YOUR_CLIENT_ID',
scopes: ['name', 'email'],
environment: 'production',
baseUrl: 'https://api.kiauth.com'
});
kiauth.renderButton('#login-container', {
text: 'Login with Kiauth',
// onSuccess receives the VERIFIED USER — the SDK completes the code exchange
// for you. It does not hand you a raw `code`.
onSuccess: (user) => {
if (!KiauthSDK.isProductionTrustworthy(user)) return; // see §1
createSessionFor(user.userToken);
},
onError: (err) => console.error(err.message)
});
</script>
<div id="login-container"></div>Option B — npm:
npm install @kiauth/web-sdkimport { KiauthSDK, isProductionTrustworthy } from '@kiauth/web-sdk';
const kiauth = new KiauthSDK({
clientId: process.env.KIAUTH_CLIENT_ID,
scopes: ['name', 'email'],
environment: 'production',
baseUrl: 'https://api.kiauth.com'
});1. Verified Human
onSuccess(user) hands you a graded identity claim. Never trust the bare boolean.
kiauth.renderButton('#login-container', {
onSuccess: (user) => {
// ❌ Not enough — `kiauth_verified` is ALSO true for Kiauth's test identities.
// if (user.kiauth_verified) { ... }
// ✅ The check a production app should make:
if (!isProductionTrustworthy(user)) {
return showError('We could not verify your identity.');
}
// user.userToken — stable + pairwise. The SAME human always maps to this token
// at YOUR app, and to a different one at every other app.
// Key your account record on it.
// user.uniqueness — 'one_account_per_human'. One real human holds at most one
// account at your app — not even by deleting their Kiauth
// account and re-registering.
createAccount({ kiauthUserToken: user.userToken, name: user.name, email: user.email });
},
onError: (err) => console.error(err.message)
});isProductionTrustworthy(user) is exactly
user.kiauth_verified && user.assurance_level === 'aadhaar' && !user.is_test_identity.
It is also available as KiauthSDK.isProductionTrustworthy for script-tag users.
The KiauthUser object
| Field | Type | Meaning |
|---|---|---|
| kiauth_verified | boolean | Kiauth ran an identity check and it passed. Also true for test identities. |
| verified | boolean | Alias of kiauth_verified. Both are always present. |
| identity_verified | boolean | The durable fact that this human completed Aadhaar verification. Never decays. |
| assurance_level | 'aadhaar' \| 'human' \| 'test' \| 'none' | How strong the check was. |
| is_test_identity | boolean | TRUE for a fabricated identity from Kiauth's test mode. Reject in production. |
| uniqueness | 'one_account_per_human' | Kiauth's guarantee. |
| userToken | string | Stable, pairwise per (human, your app). Key your account on it. |
| method | 'aadhaar_okyc' \| 'peer' \| 'test_identity' \| 'none' | |
| verified_at | string | null | ISO timestamp of the identity check. |
| verification_expires_at | string | null | When Kiauth will ask them to renew. |
| assurance_age_days | number | null | How old the check is, in whole days. |
| assurance_fresh | boolean | Whether it is inside Kiauth's current freshness window. |
Re-verification is Kiauth's job, not yours. Kiauth periodically re-checks each
human; that cadence is a Kiauth↔user relationship. You are never forced to pay for a
fresh check because our clock ran out. If your own risk rules genuinely need a recent
check, use the verification API's maxAssuranceAgeDays. Otherwise read
identity_verified and let us worry about it.
2. Signup / Login
renderButton() runs the whole flow: shows a QR (desktop) or opens the Kiauth app
(mobile), waits for the biometric approval, exchanges the one-time code, and calls
onSuccess(user).
kiauth.renderButton('#login-container', { onSuccess, onError });Or drive it yourself, without the button:
await kiauth.startLogin({ onSuccess, onError, onCancel });Where the code exchange happens
- Without
clientSecret(recommended for browsers) — the SDK uses PKCE and exchanges the code with no secret. - With
clientSecretin config — the SDK exchanges directly. Convenient for server-side or sandbox use. Never ship a client secret to a browser.
Verify an access token later, from your server:
const { valid, user } = await kiauth.verifyToken(accessToken);Prefer a redirect-based integration with your existing auth library (Auth.js, etc.)? Kiauth is also a standard OpenID Connect provider — see the dev-portal docs. The embedded button (this SDK) gives full white-label control; OIDC is the lowest-friction drop-in.
3. Session management + cross-app knowledge
The user sees every app they are signed into, inside the Kiauth app, and can revoke
any of them. When they do, Kiauth sends your server a SESSION_REVOKED webhook so
you can end your own session too — two-way logout.
You can also surface logins that never went through Kiauth, so the user's dashboard is complete rather than partial.
These methods require your
clientSecretand throw if called from a browser. Run them on your server.
// A user signed in with Google / password / OTP — put it on their Kiauth dashboard.
await kiauth.reportSession({
kiauthUserToken: user.userToken,
externalSessionId: yourSessionId,
authMethod: 'GOOGLE_OAUTH', // EMAIL_PASSWORD | FACEBOOK | PHONE_OTP | APPLE | PASSKEY | UNKNOWN
deviceName: 'Chrome on MacBook',
deviceType: 'DESKTOP'
});
// Don't know their userToken? Report against a verified email instead.
await kiauth.reportSessionByEmail({ email, externalSessionId, authMethod: 'EMAIL_PASSWORD' });
// Backfill many at once.
await kiauth.reportBatchSessions(user.userToken, [ /* ... */ ]);
// The user logged out of YOUR app — remove it from their dashboard.
await kiauth.logout({ externalSessionId: yourSessionId });Webhooks to handle: SESSION_CREATED, SESSION_REVOKED, PERMISSION_REVOKED.
Config
| Field | Required | Notes |
|---|---|---|
| clientId | yes | From your app in the Kiauth dev portal |
| scopes | yes | Subset of name, email, dob, gender, phone |
| environment | yes | 'production' or 'sandbox' |
| baseUrl | recommended | Backend URL. Overrides the env default. /api/v1 is appended automatically. |
| clientSecret | no | Server / sandbox only. Omit in browsers — the SDK uses PKCE. |
| redirectUri | optional | Where to return after approval |
Button customization (white-label)
renderButton(selector, options) accepts optional styling so the button can match
your brand. All are optional and backward-compatible (omit them for the default look).
| Option | Type | Notes |
|---|---|---|
| text | string | Button label (default "Login with Kiauth") |
| theme | 'purple' \| 'white' \| 'dark' | Preset look |
| size | 'small' \| 'medium' \| 'large' | |
| color | string (CSS color) | Custom background/brand color — overrides theme |
| textColor | string (CSS color) | Custom label + icon color |
| shape | 'rounded' \| 'pill' \| 'square' | Corner style |
| fullWidth | boolean | Stretch to the container width |
| logo | boolean | Show the Kiauth lock mark (default true) |
kiauth.renderButton('#login-container', {
text: 'Continue with Kiauth',
color: '#0F172A',
textColor: '#FFFFFF',
shape: 'pill',
fullWidth: true,
onSuccess: (user) => { /* ... */ },
onError: (err) => console.error(err.message)
});Changelog
1.1.0
- Fixed:
user.kiauth_verifiedwasundefinedafter a login. The backend's login exchange emittedverifiedwhile this SDK's type declaredkiauth_verified, so an app checking the documented field silently treated every verified human as unverified. Both spellings are now emitted and normalized. - Fixed: the README claimed
onSuccesshands you acodeto exchange on your server. It hands you the verified user — the SDK completes the exchange. - Added: graded identity claims —
assurance_level,is_test_identity,identity_verified,assurance_age_days,assurance_fresh,uniqueness. - Added:
isProductionTrustworthy(user)(alsoKiauthSDK.isProductionTrustworthy). - Hardened: every response is normalized and fails closed. A missing or
unrecognised field grades as unverified rather than reaching your
ifasundefined.
1.0.0
- Initial release.
