Skip to main content

docs/auth.md

Imported Content

Authentication and Authorization

Modes

  • AUTH_MODE=disabled: development mode; gateway injects a local admin auth context.
  • AUTH_MODE=jwt: bearer JWT is required on non-public routes.
  • In staging/production, AUTH_MODE=jwt is mandatory.

JWT verification paths

  1. HS256 shared secret:
  • Set JWT_SIGNING_SECRET
  • Used when AUTH_JWKS_URL is not set
  1. OIDC/JWKS:
  • Set AUTH_JWKS_URL to your identity provider JWKS endpoint
  • Set AUTH_ISSUER and AUTH_AUDIENCE
  • Gateway validates tokens with remote signing keys (RS*/ES* algorithms via JOSE)

Required claims

  • sub (required)
  • roles (non-empty array)
  • workspaceIds (non-empty array, use "*" for all)
  • exp (required in staging/production)
  • aud and iss should align with configured audience/issuer
  • jti is required for portal-only invite tokens (roles=["client_portal"]) and is checked against persisted invite records.

Portal invite JWT model (GA)

  • Invite tokens are generated from POST /api/v1/portal/invites.
  • Claims are workspace-scoped (workspaceIds) with role client_portal.
  • Invite records are persisted in portal_invites with status (active, revoked, expired).
  • Gateway auth validates portal token jti and subject against persisted invite state.
  • Revocation is immediate via POST /api/v1/portal/invites/{id}/revoke.
  • Web portal invite links now exchange invite token through POST /api/v1/portal/session/exchange and set an httpOnly session cookie (anchor_portal_session) in Next.js runtime.
  • Portal session termination is handled by POST /api/v1/portal/session/terminate + cookie clear.
  • Portal pages (/portal) are expected to run on invite-session token auth for client-facing usage; operator JWT fallback is not used for normal portal client sessions.

Web operator JWT guardrails

  • The Next.js web runtime accepts operator auth from:
    1. anchor_operator_session httpOnly cookie (set from /auth/operator)
    2. fallback ANCHOR_OPERATOR_JWT env token
  • Web pages auto-resolve workspace context when workspaceId is omitted:
    1. workspaceId query parameter
    2. first concrete workspace in ANCHOR_OPERATOR_JWT.workspaceIds
  • In production, ANCHOR_OPERATOR_JWT is required by default (ANCHOR_REQUIRE_OPERATOR_JWT).
  • In production, wildcard workspaceIds=["*"] is rejected by default for web runtime (ANCHOR_ALLOW_WILDCARD_WORKSPACE_IDS must be explicitly set to true to bypass).
  • Recommended practice: issue one operator JWT per workspace and rotate regularly.
  • Portal-only tokens (roles=["client_portal"]) are not valid for operator session sign-in.

Example payload

{
"sub": "user-123",
"roles": ["msp_admin"],
"workspaceIds": ["*"],
"aud": "anchor-gateway",
"iss": "https://auth.anchor-msp.com/",
"exp": 1999999999
}

Public routes

  • GET /health
  • GET /api/v1/openapi
  • POST /api/v1/webhooks/workflow-completed
  • POST /api/v1/integrations/github/webhook (when enabled)
  • POST /api/v1/portal/session/exchange

Non-tenant routes

  • /api/v1/platform/* routes require JWT auth but do not require x-workspace-id.
  • Use platform_admin (or msp_admin) role for platform-level configuration.