Repository navigation
Description
Summary
On any host whose WebCrypto lacks Ed25519, every authenticated request 500s as soon as the OIDC provider is enabled — which is the default whenever the MCP server is on. Reproduced on StackBlitz/WebContainer (Node 22.22.3) with @objectstack/* 16.1.0.
Symptom
Sign-in succeeds, then the first /api/v1/auth/get-session returns 500:
[Better Auth]: OperationError DOMException [OperationError]: The operation failed for an operation-specific reason
at Object.cfrgGenerateKey (builtins.js:74:3727)
at async SubtleCrypto.generateKey (builtins.js:90:10600) {
[cause]: TypeError: o.run is not a function
at Module.generateKeyPair (jose/dist/webapi/key/generate_key_pair.js:111:26)
at generateExportedKeyPair (better-auth/dist/plugins/jwt/utils.mjs:42:48)
at Module.createJwk (better-auth/dist/plugins/jwt/utils.mjs:61:58)
at resolveSigningKey (better-auth/dist/plugins/jwt/sign.mjs:76:26)
}
[AuthManager] better-auth returned error: 500
GET /api/v1/auth/jwks reproduces it with no credentials at all — that route generates the key pair on first use.
Root cause
plugin-authregisters better-auth's JWT plugin asjwt({ schema: buildJwtPluginSchema() })— nojwks.keyPairConfig, so better-auth's default EdDSA (Ed25519) applies.- WebContainer's WebCrypto has no Ed25519, so
cfrgGenerateKeythrows. - The plugin's
afterhook on/get-sessionsigns aset-auth-jwtheader for every session, so the failure hits normal cookie login — not just OAuth clients. - It is on by default in a plain dev server:
resolveOidcProviderEnabled(pluginConfig)falls back toisMcpServerEnabled(), which defaults totrue.
So an app that never asked for OIDC still gets an unusable login on such a host, and the error message points at better-auth rather than at the algorithm choice.
Workaround
OS_OIDC_PROVIDER_ENABLED=false drops the plugin and login works (verified end to end: sign-in/email 200, get-session 200, jwks 404). Apps can't do better than this today because the algorithm isn't configurable through AuthPluginConfig.
Suggested fix
Any of, roughly in order of preference:
- Pass an algorithm the host supports — e.g. probe
crypto.subtle.generateKey({name:'Ed25519'}, …)once at startup and fall back toES256when it throws. - Expose
jwks.keyPairConfigthroughAuthPluginConfigso an app can pinES256/RS256. - At minimum, catch the keygen failure and degrade the OIDC provider (there is already
getDegradedAuthFeatures) instead of 500ing the whole session path — plus an error that names Ed25519.
Environment
@objectstack/*16.1.0, Node 22.22.3, StackBlitz WebContainer- Downstream report and workaround: fix(stackblitz): turn off the OIDC provider so the demo can log in hotcrm#486
Activity
claude commentedon Aug 4, 2026
认领:PM 循环第 1 轮(identity 车道)
会话:
session_015W6nhsDrz6zWQc8je12a1t分支:
claude/issue-3585-jwt-eddsa-fallbackWorktree:
objectstack-issue-3585域:
domain:identity文件面:
packages/plugins/plugin-auth/**(预计auth-manager.ts、auth-schema-config.ts一带 + 测试 + changeset)。⛔packages/spec/**零改动 —— 若方案 2(把 keyPairConfig 暴露进AuthPluginConfig)要求改 spec 契约面,即触发 needs_decision 停下,不自行定契约形状Generated by Claude Code
claude commentedon Aug 4, 2026
PM 验收(第 1 轮,identity 车道):ACCEPT — PR #5044,CI 绿后转 ready 入队
复核逐条(对 GitHub 实况):
utils.mjs默认仍是{alg:'EdDSA',crv:'Ed25519'},jwt({schema})注册点仍在auth-manager.ts:2175—— 不是照 issue 快照施工。{name:'Ed25519'}描述符而非宿主嗅探;packages/spec/**零改动 ✓;文件面全部落plugin-auth✓(6 文件含 changeset)。resolveSigningKey会回退到getLatestKey()(不看算法),所以仅配keyPairConfig只救新部署 —— 存量sys_jwks里的 EdDSA 键仍会被选中并死在importJWK。dev 的解法:仅在无 Ed25519 的宿主上安装 better-auth 文档化的adapter.getJwks密钥环 seam,隐藏(不删除)导入不了的键,铸新 ES256 键收敛;正常宿主完全走原生读路径。行为变更边界清晰,行有回迁测试(宿主恢复 Ed25519 后 EdDSA 行复原)。auth-manager.jwt-eddsa-fallback.test.ts—— patch 的是 WebCrypto 本身而不是自家探针(探针 stub 会漏掉「选中了导不进的键」这条真实 500 路径),真管线跑通升级收敛全程。开发中试出的两个真 bug(裸undefined只把 500 上移一帧,因runAfterHooks无守卫读result.headers)已各自 pin 住。4 条上游 tripwire 钉住 better-auth 的默认算法/hook 形状/seam —— 升 rc.3+ 时会响。content/docs/全文零处宣称 EdDSA/Ed25519(反查 OIDC 正常命中),无文档因此过时。CI 目前 21 检 0 红、11 在跑;绿后转 ready 入合并队列,本单随 PR 关闭。
Generated by Claude Code
test(plugin-auth): pin the #3585 memory engine's delete to ObjectQL's…
fix(plugin-auth): choose a JWT signing algorithm the host supports (o…