Reduce ID token verification errors to a fixed category
CI / ci (push) Successful in 1m25s
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (pull_request) Successful in 1m25s

go-oidc's RemoteKeySet puts the JWKS endpoint's response body in its error
for non-200 and malformed 200 responses; Verify wrapped it and the callback
logged it. verifyError now keeps only a fixed category, plus the expiry for
an expired token. A test with a sentinel JWKS body checks it reaches
neither the returned error, the response nor the logs.

Addresses feature-review finding F03-03 on PR #24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 11:28:53 -04:00
co-authored by Claude Opus 5.5
parent 88f7d0a5fa
commit 516865ffe1
2 changed files with 85 additions and 2 deletions
+12 -1
View File
@@ -353,7 +353,7 @@ func (a *Auth) verify(ctx context.Context, code string, state loginState) (Claim
}
idToken, err := a.verifier.Verify(ctx, raw)
if err != nil {
return Claims{}, fmt.Errorf("verify ID token: %w", err)
return Claims{}, verifyError(err)
}
if subtle.ConstantTimeCompare([]byte(idToken.Nonce), []byte(state.Nonce)) != 1 {
return Claims{}, errors.New("ID token nonce mismatch")
@@ -404,6 +404,17 @@ func userinfoError(err error) error {
return errors.New("userinfo: endpoint returned an unusable response")
}
// verifyError reduces a failed ID token verification to a fixed category.
// go-oidc's error text can carry the JWKS endpoint's response body or
// token-supplied values, so only the expiry of an expired token is kept.
func verifyError(err error) error {
var expired *oidc.TokenExpiredError
if errors.As(err, &expired) {
return fmt.Errorf("verify ID token: token expired at %s", expired.Expiry.UTC().Format(time.RFC3339))
}
return errors.New("verify ID token: token or provider key set rejected")
}
// member reports whether groups contains an allowed group.
func (a *Auth) member(groups []string) bool {
return slices.ContainsFunc(groups, func(g string) bool { return slices.Contains(a.allowed, g) })