FaceCard Docs
Concepts

User tokens and JWKS

The signed ES256 token a successful enroll or match returns, and how to verify it.

Every successful POST /v1/enroll and POST /v1/match returns a user token and its expiry. The token is an ES256 JWT that lasts one hour.

Claims

ClaimValue
isshttps://api.facecard.dev
audfacecard
subThe FaceCard user id
app_idThe app the user belongs to
emailThe user's email
iat, expIssued at and expiry, in seconds since the epoch
jtiA unique token id

What the token is for

The token proves FaceCard matched a face in your app. You use it in two ways:

  1. Send it to your server and verify it, then start your own session. This is the normal flow.
  2. Call /v1/me routes with Authorization: Bearer <token> so the user can read or manage their own profile. See API reference: me.

Do not accept a token that your server has not verified. A token that arrived from the browser is just a string until you check it.

Verify online

POST /v1/tokens/verify with your secret key returns { "valid": true, "claims": {...} } or { "valid": false, "reason": "..." }. See API reference: tokens.

Verify offline with JWKS

The public signing keys are published at:

https://api.facecard.dev/.well-known/jwks.json

Any JWT library can verify the token against that key set:

import { createRemoteJWKSet, jwtVerify } from 'jose';

const jwks = createRemoteJWKSet(new URL('https://api.facecard.dev/.well-known/jwks.json'));

const { payload } = await jwtVerify(token, jwks, {
  issuer: 'https://api.facecard.dev',
  audience: 'facecard',
});
// Also check payload.app_id equals your app id.

Details to respect:

  • Choose the key by the token's kid. The signing key rotates, and during a rotation the set holds both the current and the previous public key.
  • Cache the JWKS (the endpoint sends a short cache lifetime) and refetch when you see an unknown kid.
  • Check app_id. A token from another FaceCard app is a valid FaceCard token but not a user of your app.
  • Offline verification cannot know that a user was deleted or signed out after the token was issued. A token revoked with POST /v1/me/logout still passes the JWKS check until it expires. POST /v1/tokens/verify (tokens.verify in the SDK) is the revocation aware check. For sensitive actions use it, or keep your own session short.

The SDK does this for you with verifyTokenOffline(token). See server SDK.

Signing out

POST /v1/me/logout puts the token's jti on a revocation list until the token expires. The API then rejects it with 401 token_revoked, and POST /v1/tokens/verify returns { "valid": false, "reason": "revoked" }. See /v1/me routes.

First party apps (the FaceCard consumer app itself) also receive an HttpOnly fc_session cookie. Third party apps get the token in the response body only.

On this page