TypeScript SDK for gating HTTP requests behind privacy-preserving identity verification.
It supports two providers:
selfzkpassport
When a request is not yet verified, x511 returns a verification state that can be rendered as an HTML challenge page. After successful verification, the SDK issues a short-lived claim cookie and lets the original request continue.
x511 helps you protect a route or group of routes with checks such as:
- minimum age
- allowed nationalities
- allowed or restricted issuing countries
The package provides:
- a core
x511(config)factory - framework adapters for Hono and Elysia
- an in-memory session adapter
- country-code helpers and common country groups
pnpm add x511You will also need one of the supported framework peer dependencies if you use the adapters:
pnpm add honoor:
pnpm add elysiaimport { x511 } from 'x511'
const gateway = x511({
domain: 'https://example.com',
providers: ['self', 'zkpassport'],
disclosures: {
minAge: 18,
},
})The returned object contains:
verified(request)for checking whether an incoming request is already verifiedverify(request)for handling verification-related endpointsconfigwith the resolved configuration
- A protected request calls
verified(request). - If the request is already verified, the result is
{ type: 'verified' }. - If not, the result is
{ type: 'pending' }with a generated session and provider payload. - Your app renders the built-in verification page or uses an adapter.
- The client completes verification with
SelforZKPassport. - The provider callback reaches
verify(request). - The SDK creates a short-lived claim cookie.
- The browser reloads the original page.
- A second call to
verified(request)returns{ type: 'verified' }and optionally exposes a hashed unique ID in theX-Verification-Idheader.
The package includes adapters for:
- Hono via
x511/adapter - Elysia via
x511/adapter
Both adapters:
- return the built-in verification page with HTTP status
511when verification is pending - continue the original request when verification succeeds
- set
Set-CookieandX-Verification-Idheaders when available
interface X511Config {
domain: string
basePath?: string
dev?: boolean
providers: ('self' | 'zkpassport')[]
disclosures: {
minAge: number
nationality?: CountryFilter
issuingState?: CountryFilter
}
sessionAdapter?: SessionAdapter
}domain: public origin used in verification links, for examplehttps://example.comproviders: one or more providers; empty arrays are rejecteddisclosures.minAge: minimum age required for verification
basePath: defaults to/dev: defaults tofalsedisclosures.nationalitydisclosures.issuingStatesessionAdapter
Country filters accept exactly one mode:
{ included: ['SVK', 'CZE'] }or:
{ excluded: ['RUS', 'BLR'] }Setting both included and excluded throws an error. Setting neither also throws an error.
The package exposes country utilities from src/countries.ts:
ALL_COUNTRIESEU_COUNTRIESEEA_COUNTRIESSCHENGEN_COUNTRIESASEAN_COUNTRIESMERCOSUR_COUNTRIESAMERICAS_COUNTRIESX511Country
Example:
import { EU_COUNTRIES, x511 } from 'x511/core'
const gateway = x511({
domain: 'https://example.com',
providers: ['self'],
disclosures: {
minAge: 18,
nationality: { included: EU_COUNTRIES },
},
})By default, x511 uses MemorySessionAdapter, which stores verification state in memory. That is fine for local development, but usually not enough for production because sessions disappear on process restart and are not shared across instances.
You can provide your own adapter by implementing:
interface SessionAdapter {
has(sessionId: string): Promise<boolean>
get(sessionId: string): Promise<string | undefined>
set(sessionId: string, accessToken?: string): Promise<void>
consume(sessionId: string): Promise<string | undefined>
}consume() should return the stored value and delete it in one logical step.
During successful completion, the SDK may use:
Set-Cookie: x511=...X-Verification-Id: <sha256-hash>
Cookie behavior:
- cookie name is
x511 HttpOnlySameSite=StrictPath=/Secureis enabled unlessdev === true
The verification ID is the SHA-256 hash of the provider’s unique identifier. The raw identifier is not returned directly.
The core verifier handles these internal endpoints:
GET /ssePOST /verify/selfPOST /verify/zkPOST /claim
If none matches, it returns 404.
Important: the built-in page uses basePath when calling these endpoints, but the current verify() implementation matches the raw path names listed above. If you mount the gateway under a non-root base path, your router may need to strip that prefix before forwarding the request to verify().
Current package exports from package.json:
x511x511/corex511/adapterx511/countriesx511/session
pnpm install
pnpm buildAvailable scripts:
pnpm buildpnpm dev
- The package is ESM-only.
@selfxyz/commonand@zkpassport/sdkare loaded throughcreateRequire()because of ESM compatibility issues noted in the source.- There is currently no test suite in this repository.
MIT. See LICENSE.