FrankenPHP Mercure订阅401错误主因是JWT授权失败,需确保HS256签名密钥与Caddyfile完全一致、payload中mercure.subscribe为合法绝对URI字符串数组,且Caddyfile正确配置anonymous或publisher_jwt/subscriber_jwt。

FrankenPHP Mercure 订阅返回 401 Unauthorized
401 错误说明 Mercure Hub 拒绝了订阅请求,根本原因不是网络或 CORS,而是 JWT 授权失败。FrankenPHP 的 Mercure 模块在收到 Authorization: Bearer <token> 时,会严格校验签名和 payload 字段,任一不匹配就直接返回 401。
JWT 签名密钥不一致是最常见原因
FrankenPHP Mercure 只支持 HS256,且要求 JWT 签名密钥与配置中完全一致(逐字节),包括空格、换行、编码方式。哪怕只差一个字符或用了 base64 编码过的密钥而配置里是明文,都会验证失败。
-
publisher_jwt和subscriber_jwt在 Caddyfile 中必须设为相同字符串(开发阶段可复用) - PHP 端生成 JWT 时,
JWT::encode($payload, $secret, 'HS256')的$secret必须和 Caddyfile 里写的一模一样 - 若通过环境变量注入(如
FRANKENPHP_MERCURE_JWT_KEY),确保 Docker 或启动脚本没做 trim 或转义
payload 中 mercure.subscribe 字段格式错误
Mercure 不解析 exp、iss 等通用字段,只认 mercure.subscribe(必须是字符串数组)和 mercure.publish。字段名拼错、类型不对、URI 不合法,都会导致 401。
- ❌ 错误:
"mercure.subscribe": "/api/posts/123"(不是数组) - ❌ 错误:
"mercure.subscribe": ["posts/123"](非绝对 URI,缺 scheme+host) - ✅ 正确:
"mercure.subscribe": ["https://api.example.com/posts/123"] - ⚠️ 通配符仅支持末尾:
"https://api.example.com/posts/*"可行,"https://api.example.com/*/posts"不行
Caddyfile 中未启用 anonymous 或 JWT 配置缺失
如果前端订阅时没带 Authorization 头,而 Caddyfile 里又没配 anonymous,Mercure 默认拒绝所有无凭证请求,直接 401。
立即学习“PHP免费学习笔记(深入)”;
- 开发阶段可在 Caddyfile 的
mercure块中加一行anonymous允许无 token 订阅 - 生产环境必须传 token,且确保 Caddyfile 包含完整的
publisher_jwt和subscriber_jwt配置 - 删掉
mercure块或注释掉关键行,会导致整个 Hub 不加载,请求直接 404 而非 401 —— 所以先确认 401 是真实返回,不是配置没生效
真正容易被忽略的是:FrankenPHP 的 Mercure 不会告诉你具体哪一步校验失败,它只统一返回 401。你得挨个核对密钥、payload 结构、Caddyfile 启用状态,三者缺一不可。调试时建议先用 anonymous 排除 JWT 问题,再逐步收紧权限。



















