fix(oidc): allow string boolean in email_verified userinfo schema (#14609)

## Why

When using AWS Cognito as OIDC provider, AFFiNE returns a zod parsing
error because AWS returns `email_verified` as a string in the userinfo
response.

```json
{
    "sub": "[UUID]",
    "email_verified": "true",
    "custom:mycustom1": "CustomValue",
    "phone_number_verified": "true",
    "phone_number": "+12065551212",
    "email": "bob@example.com",
    "username": "bob"
}
```

Reference:
https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html#get-userinfo-response-sample

Error returned in AFFiNE frontend:
```
Validation error, errors: [ { "code": "invalid_type", "expected": "boolean", "received": "string", "path": [ "email_verified" ], "message": "Expected boolean, received string" } ]
```

## What

I'm adjusting the existing `OIDCUserInfoSchema` to allow `z.boolean()`
and `z.enum(['true', 'false', '0', '1', 'yes', 'no'])`.
This matches with [our `extractBoolean` function in the
`OIDCProvider`](82e6239957/packages/backend/server/src/plugins/oauth/providers/oidc.ts (L269-L285)),
which already parses string as booleans in `email_verified`. But because
the userinfo response is parsed with zod first, it's failing before
reaching our `extractBoolean`.

> [!NOTE]
> We are using zod v3. In zod v4 they [added support for
`z.stringbool()`](https://zod.dev/api?id=stringbool) which would make
this easier.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Enhanced OpenID Connect provider authentication to accept flexible
formats for email verification status, including various string
representations alongside boolean values.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Kenneth Wußmann
2026-03-09 03:53:43 +01:00
committed by GitHub
parent 9c55edeb62
commit 0b47f92134

View File

@@ -37,7 +37,9 @@ const OIDCUserInfoSchema = z
preferred_username: z.string().optional(), preferred_username: z.string().optional(),
email: z.string().email(), email: z.string().email(),
name: z.string().optional(), name: z.string().optional(),
email_verified: z.boolean().optional(), email_verified: z
.union([z.boolean(), z.enum(['true', 'false', '1', '0', 'yes', 'no'])])
.optional(),
groups: z.array(z.string()).optional(), groups: z.array(z.string()).optional(),
}) })
.passthrough(); .passthrough();