Skip to content

Architecture and request flows

zero-auth is a library inside your API process. It signs and verifies JWTs, provides Express middleware, and calls application-owned hooks for stateful refresh protection.

Responsibility boundary

text
Client
  │  bearer header or cookies

Express application
  │  credential lookup, password hashing, business policy

zero-auth
  │  sign, verify, extract, protect, authorize, refresh

Application stores
  ├─ user database
  └─ Redis/database refresh state when rotation is enabled

The package never creates users, checks passwords, chooses a database, or decides resource ownership. Your application supplies a trusted user payload after its own credential checks.

Token lifecycle

text
login
  └─ application verifies credentials
      └─ zero-auth signs access + refresh tokens

API request
  └─ protect() extracts and verifies the access token
      └─ req.user is populated
          └─ authorize()/authorizePermissions() checks policy

refresh
  └─ refreshHandler() verifies the refresh token
      ├─ stateless mode: issue a new access token
      └─ rotation mode: atomically consume jti, then issue a new pair

Claims

Application claims are preserved through refresh:

ClaimPurpose
idRequired application user identifier
emailOptional application user email
roleOptional role checked by authorize()
permissionsOptional strings checked by authorizePermissions()
jtiToken identifier used for refresh rotation
fidStable refresh-token family identifier when rotation is enabled
iat / expIssued-at and expiration timestamps

Do not put passwords, secrets, or unnecessary sensitive data in claims. JWT payloads are readable by anyone holding the token even though they are signed.

Middleware ordering

ts
app.use(express.json());
app.use(auth.csrf()); // Needed for cookie-authenticated writes.

app.patch(
  "/users/:id",
  auth.protect(),
  auth.authorizePermissions(["users:update"]),
  updateUserHandler,
);

app.use(auth.errorHandler); // Last.

CSRF checks whether auth cookies are present. Bearer requests still need protect and authorization, but do not need the cookie CSRF middleware.

Stateless and stateful modes

ModeShared storageReplay detectionBest fit
Bearer, no rotationNoNoSimple APIs and internal services
Cookie, no rotationNoNoSmall browser applications
Rotating refresh tokensYes for multiple instancesYesProduction sessions requiring replay response

An in-memory revocation store is suitable for tests and one-process development. Redis or a database is required when instances restart or requests can reach different processes.

Source layout

  • src/core: JWT signing, verification, and decoding.
  • src/middleware: protection, optional auth, roles, permissions, and CSRF.
  • src/refresh: refresh handling and revocation-store helpers.
  • src/cookies: cookie setting, clearing, and parsing.
  • src/errors: typed errors and Express error responses.
  • src/types: public configuration, payload, and Express augmentation types.
  • tests: unit, integration, security, rotation, and concurrency coverage.

Failure boundaries

Invalid access tokens fail with 401. Missing roles or permissions fail with 403. Invalid CSRF values fail with 403. A rotation-store failure fails closed with 401 AUTH_TOKEN_INVALID so the server does not issue untracked tokens.