Apikee

Node.js

apikee for Node.js and TypeScript — Express, Fastify, and Hono.

Node.js

npm

Installation

npm install apikee     # or pnpm add apikee / yarn add apikee

Node 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

OptionTypeDefaultDescription
secretsstring[]requiredSigning secrets. First is current; rest for rotation.
serverKeystringundefinedapikee.dev project key. Enables server mode.
projectEnvstringundefinedapikee.dev project_env slug.
headerNamestring"x-api-key"Header to read the key from.
defaultExpiresInstring"90d"Default expiry for new keys.
autoRegisterEndpointsbooleantrueRegister endpoints on first request (server mode).
autoCreateClientsbooleantrueAuto-create client when issuing a key (server mode).
failOpenbooleantrueAllow through if server call fails.

ApikeeClaims fields

FieldTypeDescription
idstringUnique key ID
tenantstringTenant / owner
scopesstring[]Permission scopes
environmentstringEnvironment tag
expiresAtDate | nullExpiry date
notBeforeDate | nullNot-valid-before date
metaRecord<string, unknown>User-defined metadata
rawKeystringOriginal key string

Source

github.com/apikee-dev/node

On this page