authorization
Parses the Authorization request header and delegates credential
verification to one or more pluggable strategies. Each strategy defines a
scheme type, optional attribute matching, and an async authorizer function.
Pipeline stage: Authorization
Import
Section titled “Import”import { authorization } from "@centralping/ergo";Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
strategies | Array<Strategy> | [] | Authentication strategy definitions |
Strategy Object
Section titled “Strategy Object”| Property | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Scheme name (Bearer, Basic, ApiKey, etc.) |
attributes | object | No | Additional matching criteria |
authorizer | function | Yes | Async function — signature varies by scheme (see below) |
Authorizer Signatures
Section titled “Authorizer Signatures”The library parses credentials internally and calls your authorizer with
a scheme-specific signature:
| Scheme | Signature | Description |
|---|---|---|
Basic | (attributes, username, password) => { authorized, info } | Base64 decoded and split on : by the library |
Bearer | (attributes, token) => { authorized, info } | Raw token string (no decoding) |
| Custom | (attributes, credentials) => { authorized, info } | Raw credential string for any other scheme |
Return Value
Section titled “Return Value”On success, the middleware returns the info object from the matching
strategy, stored at acc.auth:
{ user: { id: "42", role: "admin" } }The shape of acc.auth is opaque — it is entirely determined by
the info value your authorizer function returns when
authorized: true. The TypeScript type is Record<string, unknown>;
consumers narrow the type via application-level assertions or generics.
Multi-scheme examples:
// Bearer — authorizer returns decoded JWT claimsacc.auth // → { user: { id: "42", role: "admin" } }
// Basic — authorizer returns validated credentialsacc.auth // → { username: "jane", permissions: ["read", "write"] }
// API Key — authorizer returns service identityacc.auth // → { service: "billing", scopes: ["invoices:read"] }Because the middleware stores whatever your authorizer provides, you
have full control over the shape. Design your info object to carry
exactly what downstream handlers need — no more, no less.
Error Responses
Section titled “Error Responses”| Status | Condition |
|---|---|
| 401 Unauthorized | Missing or invalid credentials (Bearer default; missing header with configured strategies) |
| 403 Forbidden | Default when authorized is false (Basic always; custom schemes; no configured strategies) |
| 400 Bad Request | Bearer only — authorizer returns info.type: 'invalid_request' |
The exact status code depends on the scheme. See Per-Scheme Rejection Behavior below for the full mapping.
When a strategy provides an authenticate value, ergo includes a
WWW-Authenticate response header with the challenge.
Per-Scheme Rejection Behavior
Section titled “Per-Scheme Rejection Behavior”The status code and WWW-Authenticate challenge on authorization failure
vary by scheme:
Bearer (RFC 6750)
Section titled “Bearer (RFC 6750)”When the authorizer returns { authorized: false, info }, ergo maps the
info.type field to an HTTP status code per RFC 6750 §3.1:
info.type | Status | Description |
|---|---|---|
'invalid_request' | 400 Bad Request | Malformed request (e.g. missing required parameter) |
'insufficient_scope' | 403 Forbidden | Valid token but insufficient privileges |
| (default) | 401 Unauthorized | Invalid or expired token ('invalid_token' or unset) |
The response includes a WWW-Authenticate: Bearer header with error,
error_description, and error_uri attributes derived from info.type,
info.desc, and info.uri respectively.
When the authorizer returns { authorized: false }, ergo always
responds with 403 Forbidden regardless of any statusCode or info
properties. No WWW-Authenticate header is included in the rejection
response.
Missing or Malformed Header
Section titled “Missing or Malformed Header”When the Authorization header is missing, empty, or does not match any
configured strategy:
- With configured strategies: 401 Unauthorized with a combined
WWW-Authenticateheader listing all configured scheme challenges - With no configured strategies: 403 Forbidden
Bearer Authentication
Section titled “Bearer Authentication”import { compose, authorization } from "@centralping/ergo";
const pipeline = compose( [authorization({ strategies: [{ type: "Bearer", authorizer: async (attributes, token) => { const user = await verifyJwt(token); return user ? { authorized: true, info: { user } } : { authorized: false }; }, }], }), "auth"],);router.get("/users/:id", { authorization: { strategies: [{ type: "Bearer", authorizer: async (attributes, token) => { const user = await verifyJwt(token); return user ? { authorized: true, info: { user } } : { authorized: false }; }, }], }, execute: (req, res, acc) => ({ response: { body: { userId: acc.auth.user.id } }, }),});Basic Authentication
Section titled “Basic Authentication”import { compose, authorization } from "@centralping/ergo";
const pipeline = compose( [authorization({ strategies: [{ type: "Basic", attributes: { realm: "api" }, authorizer: async (attributes, username, password) => { const user = await validateCredentials(username, password); return user ? { authorized: true, info: { user } } : { authorized: false }; }, }], }), "auth"],);router.get("/admin", { authorization: { strategies: [{ type: "Basic", attributes: { realm: "admin" }, authorizer: async (attributes, username, password) => { const user = await validateCredentials(username, password); return user ? { authorized: true, info: { user } } : { authorized: false }; }, }], }, execute: (req, res, acc) => ({ response: { body: { admin: acc.auth.user.name } }, }),});RFC References
Section titled “RFC References”Related Recipes
Section titled “Related Recipes”- Multi-Auth Strategies — Per-route auth overrides, optional auth, and API key authentication
API Reference
Section titled “API Reference”See the auto-generated authorization API docs.