Node.js
apikee for Node.js and TypeScript — Express, Fastify, and Hono.
Node.js
Installation
npm install apikee # or pnpm add apikee / yarn add apikeeNode 18+ required. Zero production dependencies.
Adapters
Import from the adapter path for your framework:
import { apikeeMiddleware, requireScope, injectSwagger } from 'apikee/express'
import { apikeePlugin, injectFastifySwagger } from 'apikee/fastify'
import { apikeeMiddleware, requireScope } from 'apikee/hono'Express
import express from 'express'
import swaggerJsdoc from 'swagger-jsdoc'
import swaggerUi from 'swagger-ui-express'
import { apikeeMiddleware, injectSwagger, requireScope } from 'apikee/express'
import { Apikee } from 'apikee'
const app = express()
const apikee = new Apikee({ secrets: ['your-signing-secret'] })
// Build your swagger spec first
const spec = swaggerJsdoc({ definition: { openapi: '3.0.0', ... }, apis: ['./routes.js'] })
// Inject ApikeeAuth security scheme — patches spec in place
injectSwagger(spec)
app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec))
// Protect all routes (excludePaths skips validation)
app.use(apikeeMiddleware({
apikee,
excludePaths: new Set(['/health', '/keys']),
}))
// Claims on req.apikee
app.get('/data', (req, res) =>
res.json({ tenant: req.apikee!.tenant })
)
// Scope guard
app.delete('/users/:id', requireScope('admin'), (req, res) =>
res.json({ deleted: req.params.id })
)Fastify
import Fastify from 'fastify'
import fastifySwagger from '@fastify/swagger'
import { apikeePlugin, injectFastifySwagger } from 'apikee/fastify'
import { Apikee } from 'apikee'
const fastify = Fastify()
const apikee = new Apikee({ secrets: ['your-signing-secret'] })
await fastify.register(fastifySwagger, {
openapi: { info: { title: 'My API', version: '1.0.0' } },
})
await fastify.register(apikeePlugin, { apikee })
injectFastifySwagger(fastify) // patches the swagger spec
fastify.get('/data', async (req) => ({ tenant: req.apikee!.tenant }))Hono (edge-ready)
Hono middleware works unchanged on Node.js, Cloudflare Workers, Deno Deploy, and Bun.
import { Hono } from 'hono'
import { apikeeMiddleware, requireScope } from 'apikee/hono'
const app = new Hono()
app.use('*', apikeeMiddleware({ secrets: ['your-signing-secret'] }))
app.get('/data', (c) => c.json({ tenant: c.get('apikee').tenant }))
app.delete('/users/:id', requireScope('admin'), (c) =>
c.json({ deleted: c.req.param('id') })
)Hono's c.get('apikee') is fully typed via ContextVariableMap — no casting needed.
Key creation
const apikee = new Apikee({ secrets: ['your-signing-secret'] })
const key = await apikee.create('acme-corp', {
scopes: ['read', 'write'],
expiresIn: '90d', // also: '24h', '3600s', new Date(...), milliseconds
meta: { plan: 'pro' },
// server mode extras:
// name: 'Acme Mobile Backend',
// clientType: 'service',
// templateId: 'clt_abc123',
// ipWhitelist: ['203.0.113.0/24'],
})Configuration reference
| Option | Type | Default | Description |
|---|---|---|---|
secrets | string[] | required | Signing secrets. First is current; rest for rotation. |
serverKey | string | undefined | apikee.dev project key. Enables server mode. |
projectEnv | string | undefined | apikee.dev project_env slug. |
headerName | string | "x-api-key" | Header to read the key from. |
defaultExpiresIn | string | "90d" | Default expiry for new keys. |
autoRegisterEndpoints | boolean | true | Register endpoints on first request (server mode). |
autoCreateClients | boolean | true | Auto-create client when issuing a key (server mode). |
failOpen | boolean | true | Allow through if server call fails. |
ApikeeClaims fields
| Field | Type | Description |
|---|---|---|
id | string | Unique key ID |
tenant | string | Tenant / owner |
scopes | string[] | Permission scopes |
environment | string | Environment tag |
expiresAt | Date | null | Expiry date |
notBefore | Date | null | Not-valid-before date |
meta | Record<string, unknown> | User-defined metadata |
rawKey | string | Original key string |

