Authorize
Don't just authenticate the user. Prove they approved the action.
Authentication proves who is present. Some actions need more. Identizen sends the exact action to a person's trusted phone, asks for a biometric approval, and returns a signed assertion bound to that request.
Examples
-
On the phone
Approve wire of $82,419.00 to Acme Manufacturing?
Approve
-
On the phone
Deploy commit 18acb21 to production?
Approve
-
On the phone
Grant Global Administrator to jordan@example.com?
Approve
-
On the phone
Release this medical record to Dr. Okafor?
Approve
-
On the phone
Let the purchasing agent buy 500 units from Vendor X for $14,200?
Approve
The person sees the action on the device they trust and approves it biometrically. The index checks both signatures on the assertion before it answers, and your server receives the result together with the assertion itself. Human intent, cryptographically verified.
How it works
Bind once. Ask any time.
Works as the primary login or next to the one you already have. After the phone is bound, any backend can request an approval through the Verification API and wait for the answer by polling or a signed webhook.
One rule keeps the guarantee honest: your server composes the text the person reads. Never let a client, a form, or an agent write it.
// 1. Bind once. The person signs in with their phone (or enrolls next to your existing login).
// Store the per-site identifier from the id_token.
const { claims } = await idz.exchangeCode({ code, codeVerifier, redirectUri });
await users.update(userId, { idzSub: claims.sub }); // 2. Later, from any backend, send the exact action. Your server composes the text.
import { createIdentizenServer } from '@identizen/sdk/server';
const idz = createIdentizenServer({ indexUrl, clientId, clientSecret });
const v = await idz.verify({
sub: user.idzSub,
reason: 'Approve wire of $82,419.00 to Acme Manufacturing?',
});
const done = await idz.waitForVerification(v.verification_id);
// 3. Act only on an approval. The assertion binds the hash of the reason the person read.
if (done.status === 'approved') await wires.release(wire.id); What the signature covers
Five things, all at once.
- The site
- The registered client and its origin. An approval for one site is meaningless to another.
- The person
- The per-site identifier, signed by a key only that phone holds.
- The action
- A hash of the exact text shown on the phone. Change one character and the signature fails.
- The moment
- A nonce and a 60-second expiry. Nothing can be captured and replayed later.
- The proof
- How it was approved, face or fingerprint, in the amr claim, plus the device that signed.
The formats are specified, the test vectors are public, and the index is open source and self-hostable, so nothing here depends on trusting us. See the protocol.
Agents
Let agents act. Keep humans in control.
The same primitive puts a person between an AI agent and any action you decide is consequential. The agent asks, the app's server composes the request, the phone shows it, and the agent continues only with a signed approval in hand.
See a wire approved at the demo bank.
JT Merlin Bank is a fictional bank that uses exactly this flow for every wire and for any transfer of $1,000 or more. Its developer pages show the source.