Capacitor原生应用对接Azure AD跨域令牌兑换错误排查
错误信息
AADSTS9002326: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type. Request origin: 'http://localhost:4200'.
使用的框架与工具
- Angular: 11.0.0
- Angular OIDC Client: 11.6.8
- Capacitor: 3.0.0
- Azure AD: 身份认证服务
认证流程
原生应用打开浏览器发起Azure AD认证,认证完成后Azure AD通过自定义URI scheme重定向回应用。
相关配置
1. Angular OIDC Client认证配置
import { PassedInitialConfig } from 'angular-auth-oidc-client'; const isNative = true; export const authConfig: PassedInitialConfig = { config: { authority: 'MyAuthority', redirectUrl: isNative ? 'msauth.laadpalen.monitor.native://auth' : 'http://localhost:4200', postLogoutRedirectUri: isNative ? 'msauth.laadpalen.monitor.native://auth' : 'http://localhost:4200', authWellknownEndpointUrl: 'MyEndpoint', clientId: 'MyClientID', scope: 'MyScope', responseType: 'code', silentRenew: true, useRefreshToken: true, maxIdTokenIatOffsetAllowedInSeconds: 600, issValidationOff: false, autoUserInfo: false, customParamsAuthRequest: { prompt: 'select_account', }, } }
2. iOS配置(Info.plist)
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleTypeRole</key> <string>Editor</string> <key>CFBundleURLName</key> <string>laadpalen.monitor.native</string> <key>CFBundleURLSchemes</key> <array> <string>msauth.laadpalen.monitor.native</string> </array> </dict> </array>
3. Capacitor配置(capacitor.config.json)
{ "appId": "stage.optis.cloud.laadpalen.monitor", "appName": "laadpalen-monitor-fe", "webDir": "dist/browser", "server": { "url": "http://localhost:4200" }, "packageClassList": [ "AppPlugin" ] }
4. Azure AD配置
重定向URI:
- http://localhost:4200(Web端使用)
- msauth.laadpalen.monitor.native://auth(原生应用使用)
问题现象
浏览器通过自定义URI scheme重定向回应用后,触发上述跨域令牌兑换错误。
疑问
- 是什么原因导致了这个跨域令牌兑换错误?
- 如何解决该问题以让原生应用正常对接Azure AD完成认证?
- 同一Azure应用注册下还有其他团队的Web应用,配置了其他端口和URL的Web重定向,我这边配置了SPA和iOS,这会是错误原因吗?
已执行的排查步骤
- 确认Azure AD中的重定向URI配置正确
- 验证Azure AD中的平台类型配置
- 检查Angular应用和Capacitor的相关配置
解决方案
错误原因分析
核心问题是:原生应用兑换授权码时,请求Origin为http://localhost:4200(来自Capacitor的server.url配置),Azure AD将该Origin识别为SPA类型应用,但你的原生应用对应的是Azure AD中的「移动和桌面应用」平台,两者类型不匹配,导致跨域令牌兑换被拒绝。
同一应用注册下其他团队的Web重定向配置不会直接引发错误,只要各平台的重定向URI与对应平台类型配置匹配即可。
具体解决步骤
移除Capacitor的server.url配置
Capacitor设置server.url: "http://localhost:4200"会让应用以localhost为Origin发起请求,这是问题根源。修改capacitor.config.json:{ "appId": "stage.optis.cloud.laadpalen.monitor", "appName": "laadpalen-monitor-fe", "webDir": "dist/browser", // 移除server.url节点,或设置为空字符串 "packageClassList": [ "AppPlugin" ] }修改后应用会加载本地打包的web资源,Origin将对应原生环境而非localhost。
确认Azure AD平台类型配置
登录Azure门户进入应用注册:- 进入「认证」页面,确保
msauth.laadpalen.monitor.native://auth配置在移动和桌面应用平台下 http://localhost:4200配置在**单页应用(SPA)**平台下,不要混配平台类型
- 进入「认证」页面,确保
优化Angular OIDC Client配置
- 动态判断原生环境,避免硬编码错误:
import { Platform } from '@capacitor/core'; const isNative = Platform.isNative(); - 保持
responseType: "code"(Azure AD移动平台支持授权码流程),同时确保useRefreshToken: true以减少重复认证。
- 动态判断原生环境,避免硬编码错误:
重新打包测试
执行ng build打包Web资源,再运行npx cap sync ios同步到iOS项目,最后在Xcode中重新运行测试。
内容的提问来源于stack exchange,提问作者Toby x

