Principal to the request. A token that cannot be verified is a 401; a valid token for a role that cannot perform the requested action is a 403.
Required header
Every endpoint except/healthz, /readyz, and the provider webhook receivers requires:
OIDC tokens (human callers)
In production, MeetCost verifies bearer tokens as JWTs against your configured OIDC issuer. SetMEETCOST_OIDC_ISSUER to your IdP’s issuer URL (e.g. https://accounts.google.com for Google Workspace, or your Entra tenant endpoint). MeetCost performs OIDC discovery automatically to find the JWKS endpoint.
- A valid signature against the IdP’s published JWKS keys
- A non-expired
expclaim - The correct
ississuer - The configured
MEETCOST_OIDC_AUDIENCE(if set)
MEETCOST_OIDC_EMAIL_CLAIM (default: email), then falls back to preferred_username.
The add-in clients (Google Meet, Zoom, Teams) pass the identity token that the host platform already issued them. End users never handle tokens directly — the add-in passes it automatically.
Service tokens (machine callers)
Webhook relays, cron jobs, CI pipelines, and any other non-human caller use a static bearer token fromMEETCOST_SERVICE_TOKENS. This environment variable holds a comma-separated list of name:token pairs:
admin role. Service tokens should be long random strings, rotated like any privileged secret.
Development tokens
In a non-production deployment (MEETCOST_ENVIRONMENT anything other than production or prod), you can mint a short-lived development token with:
Authorization header. Development tokens are refused in production — the server returns 401 with the detail "auth_mode=dev is refused in production".
Role resolution
After the token is verified and the email extracted, MeetCost looks up the caller’s role from theuser_roles table. The absence of a row means participant — the least-privileged option, so a directory sync that adds a new person never accidentally grants elevated access.
Roles
Roles form a hierarchy:
admin satisfies any check for finance, team_lead, organiser, or participant. finance satisfies team_lead, and so on.
401 vs 403
- 401 Unauthorized — The token is missing, malformed, expired, or signed by an unrecognised key. The
WWW-Authenticate: Bearerheader is set. The client should re-authenticate. - 403 Forbidden — The token is valid, but the caller’s role does not permit the requested action. Re-authentication will not help; the caller needs a role change.