-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
Backend: Multi-issuer token validation
Epic: Multi-IdP Authentication (#150)
Blocked by: Per-IdP ALB listener rules (for E2E, but code can be developed first)
Summary
Update the Go backend to validate JWT tokens from multiple OIDC issuers (Okta and Entra ID). Currently, token.go fetches signing keys from a single TokenKeyUrl and middleware.go performs no issuer validation.
Current State
Config (backend/internal/config/config.go:35-39)
Auth struct {
HS256_SECRET string `env:"AUTH_HS256_SECRET"`
TokenKeyUrl string `env:"AUTH_TOKEN_KEY_URL"` // single key URL
HeaderField string `env:"AUTH_HEADER_FIELD"` // single header
}Token validation (backend/cmd/api/internal/auth/token.go:44-48)
// Fetches keys from single URL, no issuer check
url := cfg.Auth.TokenKeyUrl + kidMiddleware (backend/cmd/api/internal/auth/middleware.go:39)
// Email-only lookup, no issuer validation
user, err := model.FindUserByEmail(r.Context(), claims.Email)Requirements
Config Changes
- Replace flat
Authstruct with multi-provider config - Support loading provider configs from env vars or Secrets Manager
- Each provider needs:
issuer,token_key_url,email_domain(optional) - Preserve HS256 local dev path unchanged
Example structure:
Auth struct {
HS256_SECRET string `env:"AUTH_HS256_SECRET"`
HeaderField string `env:"AUTH_HEADER_FIELD"`
Providers []AuthProvider
}
type AuthProvider struct {
Name string // "okta", "entra"
Issuer string // expected iss claim
TokenKeyUrl string // JWKS/key endpoint base URL
}Token Validation (token.go)
- Parse JWT header to get
kidand peek at unverifiedissclaim - Look up
issagainst configured providers to find correctTokenKeyUrl - Fetch signing key from matched provider's key endpoint
- Reject tokens with unknown issuers
- Key caching should be per-provider (already keyed by
kid, should be fine ifkidvalues don't collide across providers — consider namespacing cache keys asissuer:kid)
Middleware (middleware.go)
- After token validation, verify
issclaim matches a configured provider - Log which provider authenticated the request (for debugging)
- Continue with email-based user lookup (unchanged)
Unit Tests
- Test token validation with mock Okta-issued token
- Test token validation with mock Entra ID-issued token
- Test rejection of token with unknown issuer
- Test that HS256 local dev tokens still work
- Test key caching behavior with multiple providers
Files to Modify
backend/internal/config/config.go— multi-provider auth config struct + loadingbackend/cmd/api/internal/auth/token.go— issuer-aware key resolutionbackend/cmd/api/internal/auth/middleware.go— issuer validationbackend/cmd/api/internal/auth/token_test.go— new/updated testsbackend/cmd/api/internal/auth/middleware_test.go— new/updated tests
Acceptance Criteria
- Backend validates tokens from multiple configured OIDC issuers
- Tokens with unknown
issclaims are rejected with 401 - HS256 local dev tokens continue to work
- Key cache handles multiple providers without collision
-
make test-unitpasses - No regression in Emberfall E2E tests
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels