从 spa 请求 oidc 访问令牌

Requesting oidc access token from spa

我正在尝试为 React 单页应用程序实现带有 keycloak 的 oidc 客户端。

React 前端需要访问 Java-API,这需要来自配置的 oidc 服务器(在我的例子中是 keycloak)的签名 JWT。

我们希望避免在 react-application 中存储 client-secret,因为这似乎是一种相当糟糕的做法(顾名思义)。

我在使用“隐式流”时设法得到它 运行;但是,我无法将其升级为类似“使用 pkce 的授权代码流”之类的东西,如 this.

等文章中所述

我目前正在使用以下查询参数向 /auth/realms/Test/protocol/openid-connect/auth 发送请求:

client_id = "client_id";
response_type = "code";
redirect_uri = "http://localhost/login.html";
scope = "openid";
nonce = "eGT0IRjpaz-USQSg2hoipYb3TEBAaSce";
code_challenge = "ZjFmNzM1YTBlMmMzZjk5MjMwNTk5NzE2Y2Q3M2MxZTdlYzhhYjVkYzRkN2YzN2EyYTBmYWJiNDUw";
code_challenge_method = "S256";

到目前为止这有效,我在 login.html 网站上收到 session_state 和代码作为查询参数。

然而,这就是我的困惑开始的地方:

  1. 为什么有这么多查询参数,它们不应该在散列中,这样就不会将响应发送到服务器吗?
  2. 如何继续?

据我所知,下一步是通过调用 /token 端点将这些值交换为实际令牌。

但是当我这样做时,keycloak 有时会开始抱怨缺少 client_secret,我不想提供。

示例参数(形式 url 编码):

grant_type = authorization_code
code = <response from /auth>
redirect_uri = http://localhost/login.html
client_id = client_id
client_session = <response from /auth>

所以我的问题是:我哪里出错了?

似乎我正在使用另一个流程但没有意识到,完全误解了流程或者我只是没有提供特定参数而 keycloak 抱怨另一个。

您需要发送一个code_verifier字段来兑换令牌的授权码。查看我的 blog post.

第 4 步和第 8 步中的消息

目标是使用一个库来为你做这件事,就像在 this class of mine 中我只需要调用 signInRedirectCallback.

查询字符串中的授权码return是标准的。它只能使用一次,如果以某种方式被拦截,攻击者将无法使用它,因为他们没有代码验证器。

短期

您将正确实施 SPA 的 PKCE 基础知识,这应该让您起床 运行宁愿一段时间。

长期

SPA 安全性比您想象的要复杂,2021 年不再建议仅在浏览器中实现它。如果您以后 运行 在访问令牌续订等方面遇到问题,请参阅 these Curity resources