Skip to content

[WIP] OIDC Auth provider#2536

Draft
tvi wants to merge 2 commits intomainfrom
t/jwt
Draft

[WIP] OIDC Auth provider#2536
tvi wants to merge 2 commits intomainfrom
t/jwt

Conversation

@tvi
Copy link
Copy Markdown
Contributor

@tvi tvi commented May 1, 2026

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):

{
  "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" } }
    }
  ]
}

@tvi tvi force-pushed the t/jwt branch 7 times, most recently from 1e69cc3 to b012bf3 Compare May 2, 2026 01:30
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants