Skip to content

Hono

bash
npm install hono x511

Full example

ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import { x511, self, zkpassport } from 'x511/hono'

declare module 'hono' {
  interface ContextVariableMap {
    x511: { uniqueId?: string }
  }
}

const app = new Hono()

const { verify, verified } = x511({
  domain: 'https://your-app.example.com',
  basePath: '/x511',
  dev: true,
  mode: { type: 'session', ttl: 1800 },
  disclosures: {
    minAge: 18,
    nationality: { excluded: ['RUS'] },
  },
  providers: [
    self({ scope: 'self-playground', appName: 'Backend Demo' }),
    zkpassport(),
  ],
})

app.use('*', verify)

app.get('/home', verified, (c) => {
  const identity = c.get('x511')
  return c.text(identity?.uniqueId ?? 'anon')
})

serve({ fetch: app.fetch, port: 8000 })

Mounting

verify is a Hono middleware. Mount it once on '*' (or any prefix that catches ${basePath}/*); it short-circuits when the request matches an internal X511 route and calls next() otherwise.

ts
app.use('*', verify)

verified is the route gate. Attach it as middleware on any route that should require an identity proof:

ts
app.get('/adults-only', verified, handler)
app.use('/api/admin/*', verified) // protect a whole subtree

When the cookie is valid, verified calls c.set('x511', { uniqueId }) and continues; otherwise it sets status 511 and returns the verification HTML page.

Reading the identity

ts
declare module 'hono' {
  interface ContextVariableMap {
    x511: { uniqueId?: string }
  }
}

app.get('/me', verified, (c) => {
  const { uniqueId } = c.get('x511') ?? {}
  return c.json({ uniqueId })
})

Augmenting ContextVariableMap is the standard Hono pattern for typing c.get() / c.set(). Without it, c.get('x511') widens to unknown.

Tips

  • Middleware ordering — register verify before any handler that depends on basePath-prefixed routes; otherwise an unrelated handler may match first.
  • Selective protection — call verified per route or per subtree rather than globally. The 511 page assumes the request is a navigation; mounting verified globally on JSON-only APIs gives clients the HTML page when they expected JSON.
  • Custom error responsesverified always returns the HTML page on failure. If your route is API-only, gate access manually with the core coreVerified returned from the x511/core entry point.

Native Request required

Internally the Hono adapter reads c.req.raw, which must be a native WinterTC-compatible Request instance. Hono on Bun, Deno, Cloudflare Workers, Node (via @hono/node-server), and Vercel Edge all satisfy this — no extra work needed.