Skip to content

AdonisJS

bash
npm install @adonisjs/core x511

Full example

ts
// start/routes.ts
import router from '@adonisjs/core/services/router'
import { x511, self, zkpassport } from 'x511/adonis'

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

router.use([verify])

router
  .get('/adults-only', (ctx) => {
    const identity = (ctx as any).x511 as { uniqueId?: string } | undefined
    return `Welcome, ${identity?.uniqueId ?? 'anon'}!`
  })
  .use(verified)

Mounting

verify and verified are AdonisJS-style middleware: (ctx, next) => Promise<void>.

  • router.use([verify]) registers verify globally. It hands the request to the core implementation (after normalizing AdonisJS's request to a native Request); when the path matches an internal X511 route it writes the response and returns. Otherwise it calls next().
  • Per-route .use(verified) (or .group(...).use(verified)) gates a specific route or group on the X511 cookie.

Reading the identity

The Adonis adapter writes ctx.x511 = { uniqueId } on the HTTP context. The Adonis context type is open by design, so the cast above (as { uniqueId?: string }) is the simplest pattern; for stricter typing extend HttpContext in your application's type declarations.

Tips

  • Selective protection — prefer .use(verified) on individual routes (or groups) rather than router.use([verified]). The 511 response carries an HTML page and is intended for browser navigations.
  • Native Request normalization — the adapter converts the Adonis context into a Fetch Request internally, flattening multi-value headers with comma separation. You do not need to do this yourself.
  • Response forwarding — when an internal X511 route matches, the adapter copies the resulting Response's status, headers, and body onto ctx.response. The body is forwarded as text; the SSE stream therefore renders correctly only when AdonisJS's response is not buffered upstream.