Backend Phase B (2/2): OIDC auth + config validation
- internal/auth/oidc.go: OIDCService mit go-oidc v3
- id_token-Verifikation via JWKS (Signatur, iss, aud, exp)
- Provider-Caching (sync.Map, lazy init per Issuer-URL)
- Unterstützt Google + Generic OIDC
- internal/auth/user.go: GetByOIDCSubject + CreateOIDCUser
(find-or-create via (oidc_issuer, oidc_subject))
- internal/httpapi/auth.go: POST /auth/oidc Handler
(id_token verifiziern → find-or-create User → issueSession)
- internal/httpapi/api.go: /auth/oidc Route verdrahtet
- internal/config/config.go: OIDC-Validierung
(enabled → client_id + issuer Pflicht)
- go.mod/go.sum: go-oidc/v3 + oauth2 Abhängigkeiten
- AGENTS.md: Phase B vollständig als erledigt markiert
Verifiziert: E2E gegen lokalen Mock-IdP (Discovery → JWKS →
signiertes id_token → User angelegt → 2. Login gleicher User →
tampered Token → 401). Alle Fehlerpfade geprüft.
go build ./... && go vet ./... && go test ./internal/auth/... ✅
This commit is contained in:
parent
7b1c18590e
commit
a5ef8cf3ba
8 changed files with 322 additions and 23 deletions
|
|
@ -63,8 +63,32 @@ func Load() (*Config, error) {
|
|||
if err := env.Parse(&cfg); err != nil {
|
||||
return nil, fmt.Errorf("parse env: %w", err)
|
||||
}
|
||||
if err := cfg.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// validate enforces invariants that env parsing alone can't express.
|
||||
func (c *Config) validate() error {
|
||||
if c.GoogleOIDC.Enabled {
|
||||
if c.GoogleOIDC.ClientID == "" {
|
||||
return fmt.Errorf("OIDC_GOOGLE_ENABLED=true requires OIDC_GOOGLE_CLIENT_ID")
|
||||
}
|
||||
if c.GoogleOIDC.Issuer == "" {
|
||||
return fmt.Errorf("OIDC_GOOGLE_ENABLED=true requires OIDC_GOOGLE_ISSUER")
|
||||
}
|
||||
}
|
||||
if c.GenericOIDC.Enabled {
|
||||
if c.GenericOIDC.ClientID == "" {
|
||||
return fmt.Errorf("OIDC_GENERIC_ENABLED=true requires OIDC_GENERIC_CLIENT_ID")
|
||||
}
|
||||
if c.GenericOIDC.Issuer == "" {
|
||||
return fmt.Errorf("OIDC_GENERIC_ENABLED=true requires OIDC_GENERIC_ISSUER")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsProduction reports whether the app runs in production mode.
|
||||
func (c *Config) IsProduction() bool { return c.AppEnv == "production" }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue