fix#13938fix#14683fix#14532
#### PR Dependency Tree
* **PR #14686** 👈
This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Flexible OIDC claim mapping for email/name, automatic OIDC discovery
retry with exponential backoff, and explicit OAuth flow modes (popup vs
redirect) propagated through the auth flow.
* **Bug Fixes**
* Stricter OIDC email validation, clearer error messages listing
attempted claim candidates, and improved callback redirect handling for
various flow scenarios.
* **Tests**
* Added unit tests covering OIDC behaviors, backoff scheduler/promise
utilities, and frontend OAuth flow parsing/redirect logic.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## 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`](https://github.com/KennethWussmann/AFFiNE/blob/82e6239957db5f3754cde8ad968db62bc4ffad6a/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 -->
## 📝 Summary
This PR fixes a regression that caused the following error during GitHub
OAuth login:
> Unable to parse JSON response from
[https://github.com/login/oauth/access_token](https://github.com/login/oauth/access_token)
Related issue:
[https://github.com/toeverything/AFFiNE/issues/14334](https://github.com/toeverything/AFFiNE/issues/14334)
Regression introduced in:
[https://github.com/toeverything/AFFiNE/pull/14061](https://github.com/toeverything/AFFiNE/pull/14061)
---
## 🎯 Background
GitHub’s OAuth access token endpoint returns different response formats
depending on the request headers.
To receive a JSON response, the request must include:
```
Accept: application/json
```
If the `Accept` header is missing, GitHub responds with:
```
application/x-www-form-urlencoded
```
The current implementation assumes a JSON response and parses it
directly.
When a non-JSON response is returned, JSON parsing fails,
breaking the OAuth login flow.
---
## 🔍 Traffic Analysis (tcpdump)
Network path:
affine-graphql → (HTTPS) → envoy → (HTTP, tcpdump) → envoy → GitHub
### Observed Request
```
POST /login/oauth/access_token HTTP/1.1
host: github-proxy.com
content-type: application/x-www-form-urlencoded
accept: */*
...
```
### Observed Response
```
HTTP/1.1 200 OK
date: Sat, 28 Feb 2026 14:47:43 GMT
content-type: application/x-www-form-urlencoded; charset=utf-8
...
```
The `Accept` header was `*/*` instead of `application/json`,
causing GitHub to return a form-urlencoded response.
---
## 🐛 Root Cause
PR #14061 introduced a side effect in the request configuration.
Although the `Accept` header was initially defined,
the request options were later overwritten by the `init` parameter.
Because `init.headers` replaced the previously defined headers object,
the required header was lost.
Resulting in:
* Missing `Accept: application/json`
* GitHub returning `application/x-www-form-urlencoded`
* JSON parsing failure
* OAuth login failure
---
## 🔧 Changes
### 1️⃣ Fix header overwrite order
* Process the incoming `init` parameter first
* Explicitly overwrite required headers afterward
* Ensure `Accept: application/json` is always enforced
---
## 💥 Breaking Changes
None.
---
## 🧪 How to Test
1. Configure GitHub OAuth.
2. Attempt login via GitHub.
3. Verify that:
* The request contains `Accept: application/json`
* The response content-type is `application/json`
* No JSON parsing error occurs
* OAuth login completes successfully
---
## 📌 Notes
This change restores correct OAuth behavior and prevents regression
caused by header overwriting introduced in #14061.
The same header overwrite pattern identified in this issue
was also found in the calendar module and has been corrected there as
well.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Improved backend HTTP header handling for external integrations to
avoid unintended header overrides, ensuring content-type and encoding
hints are applied consistently and improving reliability of service
requests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
#### PR Dependency Tree
* **PR #14452** 👈
This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved null-safety, dependency tracking, upload validation, and
error logging for more reliable uploads, clipboard, calendar linking,
telemetry, PDF/theme printing, and preview/zoom behavior.
* Tightened handling of all-day calendar events (missing date now
reported).
* **Deprecations**
* Removed deprecated RadioButton and RadioButtonGroup; use RadioGroup.
* **Chores**
* Unified and upgraded linting/config, reorganized imports, and
standardized binary handling for more consistent builds and tooling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
> [!NOTE]
> **This is a reopened (already approved) PR**
> Needed to reopen https://github.com/toeverything/AFFiNE/pull/13011
because commit email was wrong and I could not sign the CLA
Make Office365 / Azure login possible by making preferred_username
optional.
This is NOT send in the token of MS.
To make this work you ALSO need to set the oidc.config.args.id to
"email" (there preferred_username is used as default)
Source:
https://github.com/toeverything/AFFiNE/blob/canary/packages/backend/server/src/plugins/oauth/providers/oidc.ts#L152
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved compatibility with OIDC providers by allowing the preferred
username field to be optional during user info validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
- **Bug Fixes**
- Improved Apple OAuth login reliability by ensuring client version checks do not block the callback process.
- **New Features**
- Enhanced OAuth account information by including an optional display name field.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---
<details open="true"><summary>Generated summary (powered by <a href="https://app.graphite.dev">Graphite</a>)</summary>
> ## TL;DR
> This pull request adds a new migration file, a new model, and new modules related to runtime settings. It also introduces a new `Runtime` service that allows getting, setting, and updating runtime configurations.
>
> ## What changed
> - Added a new migration file `migration.sql` that creates a table called `application_settings` with columns `key` and `value`.
> - Added a new model `ApplicationSetting` with properties `key` and `value`.
> - Added a new module `RuntimeSettingModule` that exports the `Runtime` service.
> - Added a new service `Runtime` that provides methods for getting, setting, and updating runtime configurations.
> - Modified the `app.module.ts` file to import the `RuntimeSettingModule`.
> - Modified the `index.ts` file in the `fundamentals` directory to export the `Runtime` service.
> - Added a new file `def.ts` in the `runtime` directory that defines the runtime configurations and provides a default implementation.
> - Added a new file `service.ts` in the `runtime` directory that implements the `Runtime` service.
>
> ## How to test
> 1. Run the migration script to create the `application_settings` table.
> 2. Use the `Runtime` service to get, set, and update runtime configurations.
> 3. Verify that the runtime configurations are stored correctly in the database and can be retrieved and modified using the `Runtime` service.
>
> ## Why make this change
> This change introduces a new feature related to runtime settings. The `Runtime` service allows the application to dynamically manage and modify runtime configurations without requiring a restart. This provides flexibility and allows for easier customization and configuration of the application.
</details>