使用OidcClient+Azure AD获取AccessToken后调用userinfo API遇CORS错误
登录后调用Microsoft userinfo API遇CORS错误排查
问题描述
已通过下方React代码完成登录并获取Access Token,但调用https://login.microsoftonline.com/{tenant-id}/openid/userinfo API时触发CORS错误。
相关代码
import React, { useEffect, useState } from 'react'; import { OidcClient } from 'oidc-client'; const LoginButton = () => { const [user, setUser] = useState(null); const handleLogin = async () => { const config = { authority: 'https://login.microsoftonline.com/{tenant-id}', client_id: '{app-id}', redirect_uri: 'http://localhost:3000', response_type: 'code', scope: 'openid profile user.read', }; const userManager = new OidcClient(config); const state = { nonce: generateNonce() }; const request = await userManager.createSigninRequest({ state }); saveState(state); // Persist the state to storage window.location.href = request.url; }; useEffect(() => { const processCallback = async () => { const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get('code'); const savedState = getState(); // Retrieve the state from storage if (code && savedState) { const config = { authority: 'https://login.microsoftonline.com/{tenant-id}', client_id: '{app-id}', redirect_uri: "http://localhost:3000", response_type: 'code', scope: 'openid profile', }; const userManager = new OidcClient(config); const response = await userManager.processSigninResponse(); const userProfile = await userManager.getUser(); setUser(userProfile); clearState(); // Clear the state from storage after successful authentication } }; processCallback(); }, []); const generateNonce = () => { // Implement your nonce generation logic here // For example, you can use a random string generator library return 'generated-nonce'; }; const saveState = (state) => { localStorage.setItem('authState', JSON.stringify(state)); }; const getState = () => { const savedState = localStorage.getItem('authState'); return savedState ? JSON.parse(savedState) : null; }; const clearState = () => { localStorage.removeItem('authState'); }; return ( <div> {user && user.profile ? ( <> <p>Welcome, {user.profile.given_name}!</p> <p>Access Token: {user.access_token}</p> </> ) : ( <button onClick={handleLogin}>Login</button> )} </div> ); }; export default LoginButton;
错误原因分析
1. 端点选择错误:login.microsoftonline.com的userinfo端点不支持前端CORS
微软的https://login.microsoftonline.com/{tenant-id}/openid/userinfo端点不允许前端浏览器发起跨域请求,该端点设计用于后端服务调用。前端获取用户信息应改用Microsoft Graph的https://graph.microsoft.com/me端点,Graph API支持配置CORS规则。
2. 代码中的权限范围不一致
登录时请求的权限范围是openid profile user.read,但回调处理时的scope仅为openid profile,缺少user.read权限——该权限是调用Microsoft Graph /me端点的必要条件,同时也会影响oidc-client获取完整用户信息的能力。
3. Azure AD应用配置问题
- 应用类型错误:若你的React应用是单页应用(SPA),需在Azure AD应用注册中将其配置为"单页应用"类型,而非"Web应用"。Web应用的授权码流默认不支持前端CORS,而SPA类型专门针对前端场景优化了CORS规则。
- CORS来源未配置:在Azure AD应用注册的"跨域资源共享(CORS)"设置中,需添加
http://localhost:3000作为允许的来源地址,确保前端请求被允许。 - 权限未授予管理员同意:若
user.read权限是应用权限而非委托权限,需确保已获取管理员同意,否则前端无法正常获取该权限对应的Access Token。
内容的提问来源于stack exchange,提问作者sandip kakade
相关产品推荐
相关产品推荐

