Auth Token Shape
Overview
Section titled βOverviewβThis document describes the four distinct service-to-service and MCP authentication mechanisms used across the ERP-Unlocked monorepo. Do not conflate them β each mechanism has its own token format, validator, and trust boundary.
| # | Mechanism | Primary Implementation | Consumers | Format |
|---|---|---|---|---|
| 1 | MCP OAuth 2.1 JWTs | packages/mcp-oauth |
apps/ops-mcp |
ES256 JWT signed by webapp BFF Authorization Server |
| 2 | MCP Service Tokens | packages/utils/src/mcp-token-validator.ts (mcp_tokens table) |
apps/ops-mcp (break-glass / service tokens), apps/webapp |
Opaque bearer token (SHA-256 hash in Postgres) |
| 3 | Internal Service Tokens | apps/webapp/src/lib/api/validate-internal-token.ts |
Internal webapp routes (/api/*/internal/*, /api/eval/*) |
Static shared secret (timingSafeEqual) |
| 4 | Cloudflare Access | Cloudflare Zero Trust edge | apps/graph-mcp, apps/internal |
CF-Access-Authenticated-User-Email identity header |
1. MCP OAuth 2.1 JWTs (packages/mcp-oauth, consumed by apps/ops-mcp)
Section titled β1. MCP OAuth 2.1 JWTs (packages/mcp-oauth, consumed by apps/ops-mcp)βInteractive MCP clients authenticate via the OAuth 2.1 + PKCE + Dynamic Client Registration flow hosted by the webapp BFF Authorization Server (packages/mcp-oauth). Note: apps/ops-mcp was retired in #4234; apps/graph-mcp uses Cloudflare Access (see Β§4).
- Signing Algorithm & Keys:
ES256asymmetric JWT signed by the webapp BFF AS and verified against/.well-known/jwks.json. - Required Claim Set:
{"iss": "https://app.ordermatic.co","aud": "ops-mcp","sub": "user_2abc123...","org_id": "org_2xyz789...","scopes": "mcp:read mcp:write","jti": "tok_...","iat": 1750000000,"exp": 1750003600}
- Claim Details:
issβ Issuer URL of the webapp BFF Authorization Server.audβ Must equal'ops-mcp'.subβ Clerk user ID.org_idβ Single Clerk organization ID bound at token issuance time.scopesβ Required space-delimited string (e.g.,'mcp:read'or'mcp:read mcp:write'), following OAuth 2.1 conventions.jtiβ Unique token identifier checked for revocation.iat/expβ Issued-at and expiration timestamps (seconds since epoch).
2. MCP Service Tokens (packages/utils/src/mcp-token-validator.ts, mcp_tokens table)
Section titled β2. MCP Service Tokens (packages/utils/src/mcp-token-validator.ts, mcp_tokens table)βNon-interactive or break-glass MCP clients use opaque bearer tokens stored in the PostgreSQL mcp_tokens table (packages/db/src/schema/).
- Format: Opaque bearer string (not a JWT).
- Validation (
packages/utils/src/mcp-token-validator.ts):- The incoming bearer token is hashed with SHA-256.
- The hash is looked up in the
mcp_tokenstable in Postgres, checkingrevoked_at IS NULLandexpires_at > NOW(). - Returns the bound organization context and
scopes: string[](stored as a PostgreSQL array / JSON array onmcp_tokens, e.g.['mcp:read', 'mcp:write']).
3. Internal Service Tokens (apps/webapp/src/lib/api/validate-internal-token.ts)
Section titled β3. Internal Service Tokens (apps/webapp/src/lib/api/validate-internal-token.ts)βMachine-to-machine calls from apps/temporal-worker, apps/email-worker, or evaluation harnesses into internal webapp endpoints (such as /api/billing/internal/*, /api/inbox-routing/internal/*, /api/eval/*) use static shared secrets injected via Infisical.
- Format: Static high-entropy secret string passed via
Authorization: Bearer <token>or a dedicated header (e.g.,X-Internal-Token/X-Eval-Token). - Validation (
apps/webapp/src/lib/api/validate-internal-token.ts):- Validated against the expected environment variable using Nodeβs
crypto.timingSafeEqual(after length normalization) to prevent timing side-channel attacks.
- Validated against the expected environment variable using Nodeβs
4. Cloudflare Access (apps/graph-mcp)
Section titled β4. Cloudflare Access (apps/graph-mcp)βInternal edge tools like apps/graph-mcp sit behind Cloudflare Access (Zero Trust) rather than performing application-level OAuth JWT verification.
- Mechanism: Cloudflare Access authenticates the user at the edge before the Worker is invoked and injects the
CF-Access-Authenticated-User-Emailidentity header. - Note:
apps/graph-mcpdoes not parsescopesclaims or verify application-level bearer JWTs in Worker code; access control is enforced by the Cloudflare Access policy.
References
Section titled βReferencesβpackages/mcp-oauth/β OAuth 2.1 ES256 JWT issuance, JWKS, and verificationpackages/utils/src/mcp-token-validator.tsβ SHA-256mcp_tokensdatabase lookup validatorapps/webapp/src/lib/api/validate-internal-token.tsβ Constant-time internal service token validatorapps/graph-mcp/src/worker.tsβ Cloudflare Access-protected MCP worker