You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo-auth-session exchangeCodeAsync对接Azure仅返回accessToken问题咨询

问题描述

我们使用Azure作为主要认证服务,通过Microsoft登录后,调用exchangeCodeAsync函数可获取到带载荷的JWT格式accessToken,但该函数仅返回accessToken,idToken和refreshToken均为undefined。请问是否需要添加或修改exchangeCodeAsync的参数?

App.tsx

import * as React from 'react';
import * as WebBrowser from 'expo-web-browser';
import {
  exchangeCodeAsync,
  fetchUserInfoAsync,
  makeRedirectUri,
  Prompt,
  useAuthRequest,
  useAutoDiscovery,
} from 'expo-auth-session';
import { Button, Text, SafeAreaView, Platform } from 'react-native';


WebBrowser.maybeCompleteAuthSession();
const clientId = '<my_client_id>';
const redirectUri = makeRedirectUri({
  path: Platform.select({
    android: 'com.example/<my_decrypted_hash_value>',
    ios: 'com.example://auth',
    default: undefined
  })
});


export default function App() {
  // Endpoint
  const discovery = useAutoDiscovery('https://login.microsoftonline.com/<my_tenant_id>/v2.0');

  // Request
  const [request, , promptAsync] = useAuthRequest(
    {
      prompt: Prompt.Login,
      clientId,
      scopes: ['https://www.example.com/API.All'],
      redirectUri,
    },
    discovery,
  );

  // functions
  const login = async () => {
    try {
      const propmtResponse = await promptAsync();
      if (request && propmtResponse?.type === 'success' && discovery) {
        const responseExchangeCode = await exchangeCodeAsync(
          {
            clientId,
            code: propmtResponse.params.code,
            extraParams: request.codeVerifier
              ? { code_verifier: request.codeVerifier }
              : undefined,
            redirectUri,
          },
          discovery,
        );
        console.log('responseExchangeCode:', responseExchangeCode); // <---------- has access token only
      } else {
        throw new Error('something went wrong');
      }
    } catch(error: any) {
      console.log('error:', error);
    }
  };

  return (
    <SafeAreaView>
      <Button
        disabled={!request}
        title="Login"
        onPress={login}
      />
    </SafeAreaView>
  );
}

app.json

{
  "expo": {
    "name": "My App",
    "slug": "My-App",
    "version": "1.0.0",
    "scheme": "msauth",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "userInterfaceStyle": "light",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.example",
      "buildNumber": "1.0.0"
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "package": "com.example",
      "versionCode": 1
    },
    "web": {
      "favicon": "./assets/favicon.png"
    }
  }
}

返回结果

返回结果

解决方案

要拿到idToken和refreshToken,需要做以下调整:

  • 补充授权请求的scopes
    Azure AD v2.0要求必须声明对应范围才能返回idToken和refreshToken:

    • openid + profile:用于获取idToken(包含用户身份信息)
    • offline_access:用于获取refreshToken(用于静默刷新accessToken)
      修改useAuthRequest的scopes配置:
    const [request, , promptAsync] = useAuthRequest(
      {
        prompt: Prompt.Login,
        clientId,
        scopes: ['openid', 'profile', 'offline_access', 'https://www.example.com/API.All'],
        redirectUri,
      },
      discovery,
    );
    
  • 验证Azure AD应用配置
    确保Azure AD应用注册的认证设置中:

    • 已启用"ID令牌"(在"高级设置"的"令牌配置"里添加或确认)
    • 允许发放"刷新令牌"(默认开启,但需确认未被禁用)
    • 重定向URI和代码中redirectUri完全匹配

调整后,调用exchangeCodeAsync就能同时获取到accessToken、idToken和refreshToken了。

内容的提问来源于stack exchange,提问作者Fiddle Freak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 12:04:56