Attestation.Server.verifier
Require an identity attestation
Creates a verifier that requires one attestation type from one issuer before issuing a payment Challenge or accepting a payment Credential. An attestation is a signed bearer token in which an issuer confirms one fact about the caller, bound to your API's origin.
Usage
import * as from 'mppx/extensions/identity/attestation'
import { , } from 'mppx/server'
const = ..({
: 'https://api.example.com',
: 'https://issuer.example.com',
: 'phone',
})
const = .({ : [.()] })
export async function (: Request) {
const = await .({ : '0.05', : [] })()
if (. === 402) return .
return .(.({ : .?.()?.. }))
}Pair it with Attestation.Client.prover. For email, use EmailOtp.Server.verifier, which wraps this verifier. See Use attestations.
Apply route policy
Return a reason from validate to reject a verified attestation with 403:
import * as from 'mppx/extensions/identity/attestation'
const = ..({
: 'https://api.example.com',
: 'https://issuer.example.com',
: 'phone',
: () =>
..('+1') ? : 'Only US and Canadian numbers are allowed.',
})Return type
Identity.Verifier<Attestation.Verified>. A successful result contains the verified claims:
type Verified = {
claims: {
aud: string // your origin
exp: number // expiry, Unix seconds
iat: number // issued at, Unix seconds
iss: string // issuer URL
jti?: string // attestation ID
sub: string // attested subject, such as a phone number
type: string // attestation type
}
}| Outcome | Status | HTTP | Identity-Attestation-Required |
|---|---|---|---|
| No attestation of this type and issuer | missing | 401 | Yes |
| No candidate verifies | invalid | 401 | Yes |
validate rejects every verified candidate | forbidden | 403 | No |
| Issuer keys can't be fetched | unavailable | 503 | No |
Identity-Attestation-Required names the type and issuer, such as phone;issuer="https://issuer.example.com", so a client prover can acquire a replacement. On 503, the client keeps its attestation.
Parameters
audience
- Type:
string | ((request: Request) => string)
Your API's public origin, which attestations must be bound to. URLs normalize to their origin, so a trailing slash matches. The function form is deprecated: it's only safe where your platform guarantees the request's host, since many Node servers build the URL from the caller's Host header.
clockTolerance (optional)
- Type:
number - Default:
60
Tolerance for iat, exp, and maxAge, in seconds.
fetch (optional)
- Type:
typeof globalThis.fetch - Default:
globalThis.fetch
Fetch for the default Attestation.Jwks.resolver. Ignored with keyResolver.
issuer
- Type:
string
Trusted issuer URL. Requires HTTPS, except HTTP on localhost or 127.0.0.1. Trailing slashes are removed.
keyResolver (optional)
- Type:
(parameters: { issuer: string; keyId: string }) => CryptoKey | undefined | Promise<CryptoKey | undefined> - Default:
Attestation.Jwks.resolver({ fetch })
Resolves the issuer's Ed25519 public key. Return undefined for an unknown key (invalid); throw only when keys can't be fetched (unavailable).
maxAge (optional)
- Type:
number
Oldest accepted iat, in seconds before now. Defaults to the attestation's own exp alone.
type
- Type:
string
Accepted attestation type, such as phone or email.
validate (optional)
- Type:
(claims: Attestation.Claims, request: Request) => string | undefined | Promise<string | undefined>
Route policy for verified claims. Return undefined to accept. Any other value, including an empty string, rejects with forbidden; a nonempty string becomes the reason.
Behavior
- Reads comma-separated tokens from
Identity-Attestation. Tokens of other types or issuers are left to their own verifiers. - Verifies at most three distinct candidates bound to your origin and unexpired, latest expiry first. A forged candidate doesn't hide a later valid one. With no usable candidate, it verifies the first matching token so the rejection says why.
- When every candidate fails,
forbiddenwins overunavailable, theninvalid. - Throws
TypeErrorat construction for an invalidissuer,clockTolerance, ormaxAge. - Treat attestations like session tokens: they're reusable at your origin until expiry. They say what the issuer checked, not what the caller may do, and don't authorize payment.