Feat v0.6.6 final hardening (#41)
All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-frontend (push) Successful in 6s
CI/CD / test-go-pg (push) Successful in 2m47s
CI/CD / test-sqlite (push) Successful in 3m1s
CI/CD / build-and-deploy (push) Successful in 29s

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #41.
This commit is contained in:
2026-03-31 17:40:40 +00:00
committed by xcaliber
parent 81c28a50bf
commit 7915d84c8b
19 changed files with 625 additions and 131 deletions

View File

@@ -218,8 +218,8 @@ func (h *AuthHandler) OIDCCallback(c *gin.Context) {
return
}
// Verify state (nonce + redirectTo retrieved but not yet validated — TODO)
_, _, err := h.stores.GlobalConfig.ConsumeOIDCState(c.Request.Context(), state)
// Verify state and retrieve nonce for ID token validation
storedNonce, _, err := h.stores.GlobalConfig.ConsumeOIDCState(c.Request.Context(), state)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid or expired state"})
return
@@ -246,6 +246,15 @@ func (h *AuthHandler) OIDCCallback(c *gin.Context) {
return
}
// Validate nonce in the ID token to prevent token replay/substitution
if tokenResp.IDToken != "" && storedNonce != "" {
if err := oidcProv.ValidateIDTokenNonce(tokenResp.IDToken, storedNonce); err != nil {
log.Printf("[auth/oidc] nonce validation failed: %v", err)
c.JSON(http.StatusUnauthorized, gin.H{"error": "nonce validation failed"})
return
}
}
// Use the ID token (or access token) to authenticate via the provider
// Temporarily set the Authorization header so Authenticate() can read it
tokenToValidate := tokenResp.IDToken