|
5 | 5 | "errors" |
6 | 6 | "fmt" |
7 | 7 | "net/http" |
| 8 | + "strconv" |
8 | 9 | "strings" |
9 | 10 | "time" |
10 | 11 |
|
@@ -181,15 +182,21 @@ func (s *OIDCService) ExtractClaims(tokens *oidc.Tokens[*oidc.IDTokenClaims], at |
181 | 182 | claims.Email = idTokenClaims.Email |
182 | 183 | } |
183 | 184 |
|
184 | | - // Check if email_verified was explicitly provided by the IdP |
185 | | - // The zitadel/oidc library returns a special type that defaults to false |
186 | | - // We need to check the raw claims to know if it was actually provided |
187 | | - if allClaims != nil { |
188 | | - if _, exists := allClaims["email_verified"]; exists { |
189 | | - claims.EmailVerifiedProvided = true |
190 | | - } |
| 185 | + // Check if email_verified was explicitly provided by the IdP. |
| 186 | + // The claim name is configurable via the attribute mapping; it falls back |
| 187 | + // to the standard OIDC "email_verified" claim. The zitadel/oidc library |
| 188 | + // returns a special type that defaults to false, so we inspect the raw |
| 189 | + // claims to know whether the IdP actually sent a value. |
| 190 | + emailVerifiedClaim := "email_verified" |
| 191 | + if attributeMap != nil && attributeMap.EmailVerified != "" { |
| 192 | + emailVerifiedClaim = attributeMap.EmailVerified |
| 193 | + } |
| 194 | + if emailVerifiedValue, exists := allClaims[emailVerifiedClaim]; exists { |
| 195 | + claims.EmailVerifiedProvided = true |
| 196 | + claims.EmailVerified = claimToBool(emailVerifiedValue) |
| 197 | + } else if emailVerifiedClaim == "email_verified" { |
| 198 | + claims.EmailVerified = bool(idTokenClaims.EmailVerified) |
191 | 199 | } |
192 | | - claims.EmailVerified = bool(idTokenClaims.EmailVerified) |
193 | 200 |
|
194 | 201 | // Extract name fields using attribute mapping or standard claims |
195 | 202 | if attributeMap != nil { |
@@ -274,3 +281,17 @@ func getClaimString(claims map[string]any, key string) (string, bool) { |
274 | 281 | } |
275 | 282 | return "", false |
276 | 283 | } |
| 284 | + |
| 285 | +// claimToBool coerces a raw claim value to a bool. IdPs normally send a JSON |
| 286 | +// boolean for email_verified, but some send the string "true"/"false". |
| 287 | +func claimToBool(v any) bool { |
| 288 | + switch val := v.(type) { |
| 289 | + case bool: |
| 290 | + return val |
| 291 | + case string: |
| 292 | + b, err := strconv.ParseBool(strings.TrimSpace(val)) |
| 293 | + return err == nil && b |
| 294 | + default: |
| 295 | + return false |
| 296 | + } |
| 297 | +} |
0 commit comments