AADSTS9002325:跨源授权码赎回需要代码交换的证明密钥。

63

我创建了一个仅属于我们组织的spa应用程序,但在请求代码时出现了问题。我该如何解决?

输入图像描述


4
尝试将平台配置从“SPA”更改为“Web”。结果是什么? - Carl Zhao
1
这很可能严重取决于您正在使用的应用程序架构(问题中未提及)。我也遇到了这个错误,尝试在 NextJs 应用程序(标准 NextJs 服务器配置 - 非自定义服务器)中使用 AzureADProvider 的 Next-Auth(v4),并将 Azure 配置设置为 SPA 平台。但是,当我切换到使用 @azure/msal-browser@azure/msal-react 时,我不得不将我的 Azure 应用程序平台切换回 SPA,以使身份验证成功。 - w. Patrick Gale
4个回答

123
我可以重现您的问题,您需要在web(而不是单页应用程序)下添加重定向URL。之后,您将能够使用认证码流程获取代码

enter image description here

类似的问题,参见:这里这里这里


添加Web平台时,您是否也保留SPA? - norgie
15
现在我收到了一个“跨域令牌兑换仅适用于‘单页应用程序’客户端类型”的错误提示。这是一个微软认证的提示信息。 - oren revenge
@orenrevenge,你能解决那个问题吗? - CMD
1
@norgie 是的,您确实需要保留两个:对于 Web,您输入 https://<your app's name>.azurewebsites.net/.auth/login/aad/callback;而对于 SPA,您只需输入 https://skywalk.azurewebsites.net。然而,在发布默认的 Blazor WASM 应用程序后,我现在看到了它的 Index 页面,但没有应用样式。这是怎么回事?! - Yoda

5
有一个问题与接受的答案不符:问题是关于SPA WEB,但提出的解决方案是将其更改为SSR WEB
对于SSR网站,使用的流程称为OAuth 2.0授权码流程,在成功登录后(302重定向),从Microsoft发送一个代码,然后将此代码交换为新的访问令牌(Microsoft内部API)。
对于SPA网站,有时没有可编程的后端服务器来提供Web文件(index.html、js、css),无法接收代码并将其交换为访问令牌。使用的流程称为OAuth 2.0隐式授权流程,在成功登录后(302重定向),直接从Microsoft返回ID令牌或访问令牌

注意:某些IAM平台正在弃用隐式授权流程

如果你正在开发一个纯React、Angular、Vue等SPA网站,而不是使用Java、C#、PHP等SSR网站或混合型网站(如Nuxt、Next等),并且你需要access_token而不是授权码(SSR),那么你应该按照以下步骤进行操作:
第一步: 将你的应用程序注册为管理员或普通用户admin

https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade

enter image description here

第二步

添加一个网络平台类型的SPA,并将重定向到您的SPA

enter image description here

第三步
勾选访问令牌复选框

enter image description here

第四步

在这一步中,您应该能够获取此类登录所需的经典值(如google、facebook、microsoft等):clientid、clientsecret、reduirect_uri、tenant等。

enter image description here

enter image description here

第五步
在spa源代码层,将authorize url中的response_type=code更改为response_type=token
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=token
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&scope=openid
&response_mode=query

附加信息

如果一切正常,所有最终用户在登录步骤时都会收到类似以下内容的提示:

enter image description here

是的,这是另一个“Azure功能”。不管怎样,是谁告诉你使用微软工具的?为了避免这种情况,通过管理员的帮助,批准它或按照这些无限步骤将您的应用标记为已验证。
参考资料:

1

不知道我是否来晚了,但我在我的React SPA应用程序中遇到了同样的问题,解决方案不是将我的应用程序更改为Web in Portal,而是解决实际问题,即我的请求中没有证明密钥。我通过创建帮助函数并将其添加到我发送用户进行身份验证的URL中来解决它:

function buildAuthorizationUrl(codeChallenge) {
    const clientId = "YOUR_CLIENT_ID":
    const redirectUri = encodeURIComponent("http://localhost:5173/auth/"); 
    // Change to url you need
    const responseType = "code";
    const scope = encodeURIComponent("openid profile offline_access User.Read");
    const state = encodeURIComponent("my_custom_state");
    return `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=${clientId}&response_type=${responseType}&redirect_uri=${redirectUri}&scope=${scope}&state=${state}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
    }
async function generateCodeVerifier() {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return Array.from(array)
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
}

async function generateCodeChallenge(codeVerifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(codeVerifier);
  const digest = await crypto.subtle.digest("SHA-256", data);

  const base64Url = (arrayBuffer) => {
    const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
    return base64.replace("+", "-").replace("/", "_").replace(/=+$/, "");
  };

  return base64Url(digest);
}

然后当用户点击登录按钮时,我添加了这个逻辑:

  const handleClick = async () => {
    const codeVerifier = await generateCodeVerifier();
    const codeChallenge = await generateCodeChallenge(codeVerifier);
    sessionStorage.setItem("code_verifier", codeVerifier);
    const authUrl = buildAuthorizationUrl(codeChallenge);
    window.location.href = authUrl;
  };

当然,如果您没有处理常见的租户,那么在buildAuthorizationUrl函数中也应进行更改。


0
我在我的组织中创建了一个相同的SPA应用程序,并为SPA创建了相同的重定向URI,由于它位于组织内部,所以我无法访问更改现有应用程序的配置。对于某些情况来说,这可能不是理想的解决方案。我通过发送PKCE信息进行身份验证和令牌请求来解决了这个问题,如OAuth所述。 首先从随机字符串生成code_verifier,然后使用code_verifier生成code_challenge
您需要在请求authorization_code时添加code_challenge,以及code_challenge_method:S256(SHA256)。 对于令牌请求,需要发送code_verifier。 以下是Curl请求示例:

授权

curl --location --request GET 'https://login.microsoftonline.com/<tenat_id>/oauth2/v2.0/authorize?client_id=<client_id>&redirect_uri=<redirect_uri>&scope=<scope>&response_type=code&response_mode=query&sate=demo&code_challenge=<code_challenge>&code_challenge_method=S256'

令牌

curl --location --request POST 'https://login.microsoftonline.com/<tenat_id>/oauth2/v2.0/token --form 'code_verifier=<code_verifier>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接