Skip to content
GuidesDocs 1.3.x

Gateway Authentication

createGatewayAuthInterceptor reads pre-authenticated identity from headers injected by an API gateway (Kong, Envoy, Traefik, etc.). The gateway has already verified the token -- the service only needs to extract the identity.

Configuration

typescript
import { createGatewayAuthInterceptor } from '@connectum/auth';

const gatewayAuth = createGatewayAuthInterceptor({
  headerMapping: {
    subject: 'x-user-id',
    name: 'x-user-name',
    roles: 'x-user-roles',
  },
  trustSource: {
    header: 'x-gateway-secret',
    expectedValues: [process.env.GATEWAY_SECRET!],
  },
});

headerMapping describes how trusted gateway headers become an AuthContext. trustSource proves that the caller is the gateway rather than a client spoofing identity headers. See GatewayAuthInterceptorOptions for the exact nested fields.

headerMapping

The headerMapping object maps AuthContext fields to the header names your gateway uses:

FieldExpected header valueExample
subjectUser ID (string)x-user-id: user-123
nameDisplay name (string)x-user-name: John Doe
rolesComma-separated rolesx-user-roles: admin,editor
scopesSpace-separated scopesx-user-scopes: read write

trustSource Check

The trustSource check verifies that the request actually came from a trusted gateway, not a direct client spoofing headers:

typescript
trustSource: {
  header: 'x-gateway-secret',
  expectedValues: [process.env.GATEWAY_SECRET!],
}

If the header is missing or the value does not match any of the expectedValues, the interceptor throws Unauthenticated.

Header Stripping

Mapped headers and the trust header are always stripped from the request after extraction. This prevents downstream services or handlers from seeing (and potentially trusting) these headers if the request is forwarded.

Full Example

typescript
import { createServer } from '@connectum/core';
import { createDefaultInterceptors } from '@connectum/interceptors';
import { createGatewayAuthInterceptor, createAuthzInterceptor } from '@connectum/auth';

const gatewayAuth = createGatewayAuthInterceptor({
  headerMapping: {
    subject: 'x-user-id',
    name: 'x-user-name',
    roles: 'x-user-roles',
  },
  trustSource: {
    header: 'x-gateway-secret',
    expectedValues: [process.env.GATEWAY_SECRET!],
  },
});

const authz = createAuthzInterceptor({
  defaultPolicy: 'deny',
  rules: [
    { name: 'admin', methods: ['admin.v1.AdminService/*'], requires: { roles: ['admin'] }, effect: 'allow' },
  ],
});

const server = createServer({
  services: [routes],
  interceptors: [...createDefaultInterceptors(), gatewayAuth, authz],
});

await server.start();