SenseCrypt Docs
Concepts

How SenseCrypt works

The passwordless, on-device biometric model — a face proof and hardware-bound key on the phone, a biometric-blind SaaS, per-sign-in rotation, and no passwords anywhere.

SenseCrypt replaces passwords with an on-device face proof combined with a hardware-bound device key. Your users prove who they are with a face scan on their phone; your application receives standard OIDC tokens or a SAML assertion. This page explains the model in enough depth that the moving parts make sense when you integrate — and, just as importantly, so you understand what SenseCrypt never sees.

No passwords, anywhere

There is no password to set, rotate, phish, or leak — not for end users, and none stored anywhere in SenseCrypt for them. Authentication is the combination of two factors the user physically controls:

  • Something they have — a device-bound key pair generated in the phone's secure hardware (Secure Enclave on iOS, StrongBox-backed Keystore on Android) during enrollment. Every call the phone makes after registration is signed with this key, and the server verifies the signature against the registered public key. This is the pop (proof-of-possession) factor.
  • Something they are — a live face match performed on the device at each sign-in, with liveness detection to defeat photos and replays. This is the face factor.

Because both factors are required on every interactive sign-in, authentication is strong multi-factor by construction — there is no "password-only" mode to downgrade to. The ID token records this: it carries amr: ["face", "mfa", "pop"] and a SenseCrypt-defined acr value asserting the face ceremony (see Tokens & sessions).

The parties in a sign-in

A browser sign-in involves four participants. Only two of them are your concern:

  1. The browser — lands on your app, gets redirected to SenseCrypt, and displays a QR code. The browser never authenticates; it just waits for the result over a live event stream.
  2. The SenseCrypt Authenticator app (the phone) — scans the QR, runs the face match locally, and reports the outcome over a signed request. Its only network peer is SenseCrypt.
  3. Your application (the relying party) — speaks standard OIDC or SAML to SenseCrypt: an authorize redirect, then a back-channel token exchange (OIDC) or an assertion POST (SAML).
  4. SenseCrypt — orchestrates the ceremony, holds all state, and mints the resulting tokens or SAML assertion.

Your integration code only interacts with parties 3 and 4 in the way you already know: a normal authorize redirect and a normal token exchange. The QR-and-face ceremony between the browser and the phone is handled by SenseCrypt and the Authenticator app.

What a sign-in looks like, step by step

Here is the full interactive OIDC ceremony. The equivalent SAML flow is identical from the phone's perspective — only the browser's entry and exit differ (see SAML).

  1. Authorize. Your app redirects the browser to SenseCrypt's authorization endpoint (OIDC) or SSO endpoint (SAML), with the standard parameters (for OIDC: response_type=code, client_id, redirect_uri, scope, state, and a PKCE code_challenge).
  2. Email entry. SenseCrypt validates the request, then shows a branded email-entry page. The email field is pre-filled from your login_hint if you supplied one. This page is byte-identical whether or not the email is known to the tenant — there is no "user exists" side channel.
  3. QR page. On submit, SenseCrypt looks up the user, snapshots their current sealed face reference onto a fresh session, and shows a QR code. The browser opens a live server-sent-events stream and waits.
  4. Scan and match. The user scans the QR with the Authenticator app. The app fetches the sealed face reference (a request gated so that only the device registered to that email can fetch it), then runs face detection, liveness, and the match — all on the phone.
  5. Report. On a successful local match, the phone recovers a secret sealed inside the face reference and reports it to SenseCrypt over a signed request, together with a freshly minted replacement face reference (single-use rotation — more below).
  6. Authorize the session. SenseCrypt verifies the reported secret with a hash comparison, marks the session authorized, mints the authorization code, and pushes an event to the browser's stream.
  7. Return and exchange. The browser returns to your redirect_uri with ?code=...&state=.... Your app completes the standard exchange at the token endpoint and receives tokens.

Your integration code only sees steps 1 and 7: a normal authorize redirect and a normal token exchange. Everything in between is the biometric ceremony.

The same seven steps as a sequence across the four participants — your app only sends the first message and receives the last:

1. Redirect to /v1/idp/oidc/authorize(client_id, redirect_uri, scope, state, PKCE code_challenge) GET /v1/idp/oidc/authorize 2. 302 to branded email-entry page(login_hint pre-fill; byte-identical whether email is known) Submit email QR page Open SSE stream /v1/browser/sessions/{id}/events (waits) 4. Scan QR → GET /v1/device/sessions/{id}/payload (signed)fetch sealed face reference (recipient-gated) sealed face reference 5. POST /v1/device/sessions/{id}/complete (signed)recovered verifier + freshly minted replacement reference SSE: authorized → redirect to redirect_uri?code=&state= 7. GET redirect_uri?code=...&state=... POST /v1/idp/oidc/token (code + PKCE code_verifier) ID token + access token (amr: face, mfa, pop) 3. Look up user, snapshot sealed face referenceonto a fresh session; render QR face proof on device — no biometric data leaves the phone(detection, liveness, and match run locally) 6. Verify BASE64URL(SHA-256(verifier)) == stored challenge;rotate reference in the same transaction; mint authorization code Your App (RP) Browser SenseCrypt Phone / Authenticator

Biometric blindness

The single most important property to internalize: SenseCrypt is biometric-blind. Face matching happens only on the device, and no face image or biometric template ever crosses the network to SenseCrypt or to your app.

Under the hood, enrollment produces a sealed, opaque reference (an AEAD-encrypted envelope) that only the same live face can open on-device. Inside that envelope is a PKCE-style secret — a code_verifier in the sense of RFC 7636. At sign-in, the phone opens the envelope locally with the live face and returns the recovered verifier. SenseCrypt stored only the verifier's SHA-256 challenge, and its entire check is:

BASE64URL_NOPAD( SHA256( face_code_verifier ) )  ==  stored face_code_challenge

That is the whole server-side "face" check — a constant-time hash comparison, structurally identical to how any OAuth server checks PKCE. SenseCrypt cannot decrypt the sealed envelope or reconstruct anything about the user's face from it. The only plaintext field it ever reads out of the envelope is a tamper-evident tenant id (used to fail-closed against cross-tenant replay); it never reads biometric data.

There is deliberately no code path anywhere in the service that decrypts a face reference. If a feature ever seems to require one, the design is wrong. See Security for the custody and key model in more depth.

Per-sign-in rotation

The sealed face reference is single-use. On every successful sign-in, the phone mints a fresh reference from the just-captured face and uploads it in the same call that reports the verifier; the server swaps the stored reference and its challenge in the same database transaction that authorizes the session. A captured-and-replayed verifier is therefore useless — the challenge it matched has already been rotated away. Failed sign-ins do not rotate, so a stable reference across failed attempts plus rotation-on-success is the observable behavior.

Enrollment and the mobile app

The SenseCrypt Authenticator is the end-user app (iOS and Android) that scans QR codes and performs the face match. Users get it from the App Store or Google Play — you do not embed it in your product, and there is no SDK to ship in your app for the sign-in itself. Users can be onboarded in three ways:

  • Admin provisioning — an operator adds a user in the admin console, optionally from an uploaded photo. This is the only flow where an image is handled by SenseCrypt: the photo is handled in-memory through an isolated sealing step, and only the returned sealed reference is persisted. The image is never written to disk, database, or logs.
  • Self-signup — a user signs up directly from the app when your application enables it. Here the phone mints the sealed reference on-device from its own camera capture; no image ever leaves the phone.
  • Directory provisioning (SCIM) — your IdP creates the user as a pending shell (a profile with group memberships but no face binding yet). The person binds their face later, on first use, through the normal app enrollment. See SCIM.

In all three cases, enrollment is always scoped to a target application — an OIDC client or a SAML SP — and the user must pass that app's access gate to enroll.

Why this matters for your app

  • No secrets to breach. You never handle passwords, and you never handle biometrics — so a compromise of your systems (or even of SenseCrypt) exposes no reusable secret for the user's identity. There is no password database to spill.
  • Strong MFA for free. Sign-in is a hardware-bound key plus a fresh, live face match on every interactive authentication. You get phishing-resistant MFA without building or operating any of it.
  • Standard integration. Because it is all standard OIDC/SAML on your side, you integrate exactly as you would with any other IdP. There is nothing biometric in your code path.
  • OIDC & OAuth 2.0 — the protocol your app speaks to run the flow above.
  • Tokens & sessions — what you receive back and the amr/acr claims that record the ceremony.
  • Security — biometric blindness, key custody, and the full threat model.
  • Add Login (OIDC) — the hands-on quickstart.

On this page