使用Expo Auth Session对接Azure ADB2C首次登录报EBADCSRFTOKEN错误
Expo Auth Session 对接 Azure ADB2C 首次登录
EBADCSRFTOKEN 错误修复方案 根因定位
该问题是Expo Auth Session代理模式与Azure ADB2C用户流跳转逻辑的兼容性问题,触发原因有两个:
- Expo Auth Session默认生成的CSRF Token与state的持久化是异步操作,首次发起授权请求时,存储未完成就已经触发了Azure跳转,B2C快速回调时本地还没有对应的校验值,导致校验失败。
- Azure ADB2C用户流首次无用户态访问时,默认会触发一次前置302跳转(用于租户选择、登录方式选择等),这次跳转丢失了Expo生成的CSRF上下文关联标记,Expo会提前清空待校验的CSRF值,等后续登录完成正式回调时校验值已不存在。
后续重试时CSRF存储已完成、B2C也已有临时会话缓存不会触发前置跳转,因此流程正常。
修复步骤
- 手动接管CSRF校验逻辑,提前持久化自定义state
不要使用Expo Auth Session自动生成的state,自己生成随机值并提前写入安全存储后再发起授权请求,代码示例:import * as SecureStore from 'expo-secure-store'; import * as AuthSession from 'expo-auth-session'; // 提前生成并存储state作为自定义CSRF校验值 const generateCustomState = async () => { const state = AuthSession.generateRandomString(32); await SecureStore.setItemAsync('auth_custom_csrf_state', state); return state; }; - 调整Azure ADB2C用户流配置
在Azure Portal的ADB2C对应「用户流」-「属性」-「会话行为」中,关闭所有非必要的前置跳转开关(如租户选择提示、统一身份提供商跳转提示等),同时将应用注册的重定向URI响应模式明确设置为query,禁用form_post模式。 - 修改授权请求触发逻辑,等待存储完成后再跳转
调整原登录触发逻辑,确保state写入完成后再初始化授权请求,回调时手动校验state匹配度:const handleLogin = async () => { // 先等待自定义state存储完成 const customState = await generateCustomState(); // 初始化授权请求 const authRequest = new AuthSession.AuthRequest({ clientId: 你的Azure ADB2C客户端ID, redirectUri: AuthSession.makeRedirectUri({ useProxy: true }), scopes: ['openid', 'profile', 'offline_access', 你的API权限范围], responseType: 'code', state: customState, extraParams: { p: 你的Azure ADB2C用户流名称, prompt: 'login' // 可选,强制跳过B2C会话缓存,避免前置跳转 }, }); // 发起授权 const authResult = await authRequest.promptAsync({ useProxy: true }); // 回调后手动校验CSRF if (authResult.type === 'success') { const savedState = await SecureStore.getItemAsync('auth_custom_csrf_state'); if (authResult.params.state !== savedState) { throw new Error('CSRF校验失败'); } // 后续用code兑换access_token逻辑 // 校验完成后删除存储的state await SecureStore.deleteItemAsync('auth_custom_csrf_state'); } };
验证方法
卸载测试设备上的应用后重新安装,连续进行10次以上首次冷启动登录测试,确认不再抛出EBADCSRFTOKEN错误,后续重试登录流程也可正常运行。
内容的提问来源于stack exchange,提问作者Nathan Klassen
相关产品推荐
相关产品推荐

