使用OAuth2连接Exchange账户时触发UnauthorizedException错误(基于garethp php-ews)
你这情况我之前也碰到过——明明拿到了access token,一调用EWS的邮件相关方法就炸401,头都大了。别慌,咱们一步步排查,大概率是权限范围或者配置细节没搞对:
1. 先把Scope改回EWS专属的!
你试的https://graph.microsoft.com/Mail.Read是Graph API的权限,EWS根本不认这个!必须用EWS对应的scope:
https://outlook.office.com/EWS.AccessAsUser.All
这个权限才是让你的应用以用户身份访问EWS的正确范围,之前的Mail.Read只适用于Graph,和EWS不搭边。
2. 去Azure AD里检查权限配置
登录Azure Portal找到你的应用注册,按这个步骤来:
- 进入「API权限」→ 「添加权限」
- 选「Office 365 Exchange Online」
- 如果是用户授权的场景,选「委派权限」;如果是服务端直接调用,选「应用权限」
- 找到并勾选
EWS.AccessAsUser.All,然后一定要点「授予管理员同意」(应用权限模式下必须做,委派权限如果是管理员账户登录也可以提前同意)
3. 解码令牌看看受众对不对
拿到access token后,去jwt.ms解码它,重点看aud字段:
- 正常应该是
https://outlook.office.com,要是显示https://graph.microsoft.com,那肯定是请求token时用错了scope或者资源地址,得改回来。
4. 确认php-ews的初始化代码没毛病
初始化API的时候,必须把用户邮箱和令牌传对,比如:
use garethp\ews\API; $api = API::withOAuth2([ 'token' => $yourValidAccessToken, 'user' => 'john.doe@yourcompany.com', // 必须指定要访问的邮箱用户 'server' => 'outlook.office365.com' ]); // 再调用方法试试 $inboxItems = $api->getMailItems('inbox');
这里的user参数不能少,EWS需要明确知道你要访问哪个用户的邮箱,尤其是应用权限模式下。
5. 检查EWS端点是否正确
Office 365的EWS端点是https://outlook.office365.com/EWS/Exchange.asmx,php-ews一般会自动处理,但如果有自定义配置,别写错了地址。
6. 看看令牌是不是过期了
解码令牌时顺便看exp字段,要是令牌已经过期,也会触发401。用授权码流程的话,记得在令牌过期前用refresh token刷新获取新的access token。
看你的错误栈,是EWS服务器直接返回401拒绝了请求,以上几个点应该能解决问题。先从scope和Azure权限配置入手,这是最常见的坑。
内容的提问来源于stack exchange,提问作者Ash




