Dashboard and API auth were tied to Supabase-specific HMAC JWT configuration
(`SUPABASE_JWT_SECRETS`) and Supabase-specific headers. That made it hard to
support other auth providers and forced provider-specific settings to spread
across several environment variables.
This change introduces one generic auth-provider JWT verification path that
supports both OIDC-compliant issuers (asymmetric keys, JWKS auto-discovered)
and non-OIDC HMAC-signed JWTs. It keeps the old Supabase headers as
compatibility aliases, while adding provider-neutral bearer token and team
header schemes.
- Add shared auth-provider JWT verification with OIDC and bearer (HMAC)
verifier strategies under `packages/auth/pkg/auth/`.
- Replace API/dashboard service-level `SUPABASE_JWT_SECRETS` with one
structured `AUTH_PROVIDER_CONFIG` JSON value, defaulted (in Terraform) to
the existing Supabase JWT secret wrapped in a `bearer` entry.
- Support multiple OIDC issuers and multiple bearer-token sources at once,
useful during migrations and multi-tenant deployments.
- For OIDC entries, fetch the discovery document at startup, cross-check
`issuer`, and resolve `jwks_uri` from it. JWKS HTTPS is required.
Lookups/caching/refresh use `github.com/MicahParks/keyfunc/v3`/`jwkset`.
Fail-fast on discovery errors.
- Per-entry audience matching with `MatchAny` (default) or `MatchAll`.
- Per-entry `claimMappings.username.claim` (default `sub`) resolves directly
to an internal UUID; no email fallback.
- Wire auth-provider bearer token and `X-Team-Id` team header in both API
and dashboard API, while keeping Supabase headers as compatibility aliases.
Example with one OIDC issuer and one bearer source (e.g. during migration or
key rotation):
```json
{
"jwt": [
{
"issuer": {
"url": "https://issuer.example.com",
"discoveryURL": "https://issuer.example.com/.well-known/openid-configuration",
"audiences": ["dashboard-api"],
"audienceMatchPolicy": "MatchAny"
},
"claimMappings": { "username": { "claim": "sub" } },
"jwksCacheDuration": "5m"
}
],
"bearer": [
{
"hmac": { "secrets": ["legacy-secret"] },
"claimMappings": { "username": { "claim": "sub" } }
}
]
}
```
Co-authored-by: Jakub Dobry <dobrac@users.noreply.github.com>
Dashboard and API auth were tied to Supabase-specific HMAC JWT configuration
(
SUPABASE_JWT_SECRETS) and Supabase-specific headers. That made it hard tosupport other auth providers and forced provider-specific settings to spread
across several environment variables.
This change introduces one generic auth-provider JWT verification path that
supports both OIDC-compliant issuers (asymmetric keys, JWKS auto-discovered)
and non-OIDC HMAC-signed JWTs. It keeps the old Supabase headers as
compatibility aliases, while adding provider-neutral bearer token and team
header schemes.
verifier strategies under
packages/auth/pkg/auth/.SUPABASE_JWT_SECRETSwith onestructured
AUTH_PROVIDER_CONFIGJSON value, defaulted (in Terraform) tothe existing Supabase JWT secret wrapped in a
bearerentry.useful during migrations and multi-tenant deployments.
issuer, and resolvejwks_urifrom it. JWKS HTTPS is required.Lookups/caching/refresh use
github.com/MicahParks/keyfunc/v3/jwkset.Fail-fast on discovery errors.
MatchAny(default) orMatchAll.claimMappings.username.claim(defaultsub) resolves directlyto an internal UUID; no email fallback.
X-Team-Idteam header in both APIand dashboard API, while keeping Supabase headers as compatibility aliases.
Example with one OIDC issuer and one bearer source (e.g. during migration or
key rotation):
{ "jwt": [ { "issuer": { "url": "https://issuer.example.com", "discoveryURL": "https://issuer.example.com/.well-known/openid-configuration", "audiences": ["dashboard-api"], "audienceMatchPolicy": "MatchAny" }, "claimMappings": { "username": { "claim": "sub" } }, "jwksCacheDuration": "5m" } ], "bearer": [ { "hmac": { "secrets": ["legacy-secret"] }, "claimMappings": { "username": { "claim": "sub" } } } ] }