启用 openid connect 必须设 use_openid_connect => true,否则不生成 id_token、不校验 nonce;issuer 需为 https 完整域名,id_lifetime 宜 ≤3600 秒,推荐 rs256 签名并正确加载密钥对,/authorize 必须校验 scope=openid,/userinfo 失败主因是 aud 不匹配、字段缺失或键名不规范。

oauth2-server-php 启用 OpenID Connect 必须设 use_openid_connect => true
不加这行配置,oauth2-server-php 就只跑纯 OAuth 2.0 流程,压根不会生成 id_token,也不会校验 nonce 或返回符合 OIDC 规范的 JWT 结构。
常见错误现象是:前端传了 response_type=code id_token,后端却只返回 code,或者调用 /userinfo 时直接 404 —— 很大概率就是漏了这个开关。
实操建议:
-
issuer必须设为 HTTPS 协议的完整域名(如https://auth.example.com),否则客户端(尤其是 iOS/Android SDK)会拒绝解析 ID Token -
id_lifetime建议设为 3600 秒以内,ID Token 本就不该长期有效;过长会导致重放风险上升 - 若使用非对称签名(推荐),需确保
private_key和public_key都已正确加载,且公钥能被客户端稳定获取(例如通过/.well-known/openid-configuration暴露)
JWT 签名算法选 RS256 而不是 HS256 的真实原因
很多 PHP 开发者图省事用 HS256,但只要涉及第三方客户端(微信小程序、iOS App、React SPA),就必须切到 RS256。
根本原因不是“更安全”,而是信任模型不同:HS256 要求所有验证方(包括前端 JS、移动 SDK)都持有同一份密钥,一旦泄露,整个认证链就崩了;而 RS256 只需服务端保管私钥,公钥可公开分发,客户端用它验签即可,完全不碰密钥。
实操建议:
- 生成密钥对时用
openssl genrsa -out private.key 2048,再导出公钥:openssl rsa -in private.key -pubout -out public.key - 在
oauth2-server-php初始化时,把private_key传给Server构造函数,把public_key用于客户端验签或UserInfoController的 JWT 解析 - 别硬编码密钥路径,用
file_get_contents()动态加载,并加is_readable()判断,避免上线后因权限问题静默失败
/authorize 接口必须校验 scope=openid 才触发 OIDC 行为
OpenID Connect 不是自动开启的附加功能,它是靠 scope 显式声明的。如果请求里没带 scope=openid,哪怕你启用了 use_openid_connect,服务器也只会当普通 OAuth 处理,不发 id_token,也不要求 nonce。
典型误操作:前端拼 URL 时写成 scope=profile email,漏掉 openid;或者后端中间件提前截断、过滤了 scope 参数。
实操建议:
- 在
AuthorizeController的handleAuthorizeRequest()之前,加一层显式检查:if (!in_array('openid', $params['scope'] ?? [])) { throw new \OAuth2\Exception\InvalidScopeException(); } - 若同时需要用户信息,应组合使用:
scope=openid profile email,其中profile和email是 OIDC 定义的标准 scope,会控制/userinfo返回字段 - 注意:OIDC 要求
response_type至少含code或id_token,单独token不合法,会报错invalid_request
/userinfo 端点返回空或 401 的三个高频排查点
这个端点看似简单,但实际部署中 70% 的失败都集中在三类配置脱节上:JWT payload 字段缺失、签名密钥不一致、audience 校验失败。
最容易被忽略的是 aud(audience)声明:OIDC 要求 ID Token 的 aud 必须精确匹配请求 /userinfo 时所用的 Access Token 的 client_id,否则 UserInfoController 会直接拒掉请求,返回 401。
实操建议:
- 检查 ID Token 的 Payload 是否包含
aud、iss、sub、exp、iat这五个必需字段;缺任意一个,/userinfo都可能拒绝服务 - 确认 Access Token 是由同一个
client_id申请的,且未被篡改;用jwt.io手动解码比对aud值 -
UserClaimsInterface实现里,getUserClaims()方法返回的数组键名必须和 OIDC spec 严格一致(如email而非user_email),否则字段不会出现在/userinfo响应中
ID Token 不是“多一个 token”那么简单,它是整个信任链的起点:从 nonce 防重放到 aud 绑定客户端,从 exp 限时到公钥验签,每一步断掉都会让前端拿到一串无法落地的字符串。最常出问题的不是代码,而是配置项之间那几处没对齐的字符串值。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











