Api

OidcHttpMiddleware

Fastify HTTP middleware that verifies OIDC/OAuth2 JWT Bearer tokens and injects user context onto the request.

OidcHttpMiddleware

OidcHttpMiddleware extends BaseMiddleware and guards Fastify HTTP routes. It verifies the Authorization: Bearer <token> header and injects the resolved user context onto the request object.

Registration

import { OidcHttpMiddleware } from "ioserver-oidc";

server.addController({
  name: "profile",
  controller: ProfileController,
  middlewares: [OidcHttpMiddleware],
});

The middleware applies to all routes of the controller. To leave some routes unprotected, split them across two controllers — one with the middleware, one without.

Request flow

  1. Extracts the Bearer token from the Authorization header
  2. Resolves OidcConfig from appHandle.oidcConfig.getConfig() (or falls back to process.env)
  3. Calls verifyOidcToken(token, config) — verifies signature, iss, aud, and expiry via remote JWKS
  4. If appHandle.users.findOrCreate(sub, { email, name }) is available, provisions the local user record on first access
  5. Rejects accounts where isDisabled === true with 403
  6. Injects auth context onto the request object and calls the route handler

Injected context

After successful authentication the following properties are available on the Fastify request object:

PropertyTypeDescription
request.substringOIDC sub claim — stable auth-service user identifier
request.userIdstringLocal DB user ID (from users.findOrCreate; falls back to sub when no users manager)
request.userRolestringPrimary role — roles[0] or "user" when roles is empty
request.rolesstring[]Full roles array from the JWT roles claim
request.permissionsstring[]Permission strings from the JWT permissions claim
request.featuresRecord<string, unknown>Feature flags/limits from the JWT features claim

In TypeScript, cast the request to any or augment the Fastify type declarations in your app to access these properties without type errors:

import type { FastifyRequest, FastifyReply } from "fastify";

class ProfileController extends BaseController {
  async getMe(request: FastifyRequest, reply: FastifyReply) {
    const req = request as any;
    reply.send({
      userId: req.userId,
      role: req.userRole,
      permissions: req.permissions,
    });
  }
}

Error responses

CodeHTTP statusCondition
ERR_AUTH_TOKEN_REQUIRED401Missing or malformed Authorization header
ERR_AUTH_TOKEN_INVALID401JWT signature/claims verification failure
ERR_USER_DISABLED403User account isDisabled === true in the local DB
ERR_USER_PROVISION_FAILED500users.findOrCreate threw an error

Response body format:

{
  "statusCode": 401,
  "error": "Unauthorized",
  "code": "ERR_AUTH_TOKEN_REQUIRED",
  "message": "Bearer token required."
}

Config caching

The OidcConfig is resolved on the first request and cached on the middleware instance for the lifetime of the server process. Restarting the server clears the cache and re-reads environment variables.

Source

src/OidcHttpMiddleware.ts

Copyright © 2026