使用 AD FS 4.0 (2016) 或更高版本获取新的刷新令牌

Getting a new refresh token with AD FS 4.0 (2016) or higher

我将 AD FS 2016 配置为支持通过 OAuth2/OpenID 使用 PKCE 授权代码授予连接对“本机应用程序”进行身份验证。我通过设置以下内容创建了一个依赖方并配置(用于测试目的)令牌生命周期:

Set-AdfsRelyingPartyTrust -TargetName MyRPT -IssueOAuthRefreshTokensTo AllDevices -TokenLifetime 3

Grant-AdfsApplicationPermission -ClientRoleIdentifier MyClient -ServerRoleIdentifier MyRPT -ScopeNames openid,profile,email

Set-AdfsProperty -SSOLifetime 7 -PersistenSsoEnabled $false

...这给了我 Access/ID 3 分钟后过期的令牌和 7(实际上是 14,见下文)分钟后过期的刷新令牌。我还禁用了 Persistent SSO,所以我没有得到会话 cookie。一切顺利。

身份验证成功后,我的客户端向 /oauth2/token 端点发出 POST 请求,并传递以下参数:

我收到了以下内容的有效回复:

{
  "access_token": "...",
  "token_type": "bearer",
  "expires_in": 180,
  "resource": "MyRPT",
  "refresh_token": "...",
  "refresh_token_expires_in": 419,
  "scope": "email profile openid",
  "id_token": "..."
}

太棒了。

然后在访问令牌到期前大约 10 秒,客户端向 /oauth2/token 发出另一个 POST 请求,这次使用以下参数:

并返回以下成功响应:

{
  "access_token": "...",
  "token_type": "bearer",
  "expires_in": 180,
  "id_token": "..."
}

请注意,这次没有返回任何刷新令牌。同样的情况又发生了四次(总共大约 14 分钟,所以 两倍 SSOLifetime 呢?)而刷新令牌仍然有效,最后,在第四次请求新访问时令牌我收到以下主体的 400 错误:

{
  "error":"invalid_grant",
  "error_description":"MSIS9615: The refresh token received in \u0027refresh_token\u0027 parameter has expired."
}

这有点道理,但是...当当前刷新令牌接近到期时间时,不应该发布一个新的刷新令牌吗?

Official Docs 对此事有些含糊:

Although refresh tokens aren't revoked when used to acquire new access tokens, you are expected to discard the old refresh token. As per the OAuth 2.0 spec says: "The authorization server MAY issue a new refresh token, in which case the client MUST discard the old refresh token and replace it with the new refresh token. The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client." AD FS issues refresh token when the new refresh token lifetime is longer than previous refresh token lifetime. To view additional information on AD FS refresh token lifetimes, visit AD FS Single Sign On Settings.

呃,什么?让我用伪代码写一下:

if (newRefreshTokenLifetime > previousRefreshTokenLifetime) {
  issueNewRefreshToken();
}

...但那将是 总是 那么,不是吗?

知道如何配置 AD FS 以便它在需要时也发出新的刷新令牌吗?理想情况下有 refresh token rotation 会很好,但一次只有一件事...

通常在 OAuth 中,刷新令牌的生命周期是在委派时设置的,当用户登录时,他们可能同意在特定时间使用特定权限。

因此,如果用户在 09:00 登录了一个 8 小时的会话,并且他们的应用程序在 10:00 刷新了一个访问令牌,如果有一个新的刷新令牌发布,那么它应该可以使用7小时。也就是说,您不能在不让用户再次参与的情况下覆盖初始授权。

正如您所说,最近的趋势是在每次访问令牌刷新时获取一个新的刷新令牌,但这只是一种保护机制,ADFS 不支持。所以我会按如下方式进行:

  • 将 SSO 生命周期设置为所需值,例如 8 小时,并将访问令牌生命周期设置为标准值,例如 30 分钟
  • 以面向未来的方式编写代码,在获得新的刷新令牌时丢弃现有的刷新令牌

在本机应用程序中刷新令牌

根据评论,您正在尝试使用 PKCE 并希望使用旋转刷新令牌,但 ADFS 不支持后者,因此您不能。

您有一个本机应用程序,其标准解决方案始终是将刷新令牌存储在仅对应用程序和用户可用的安全操作系统存储中。刷新令牌是否轮换应该无关紧要。示例:

SPA

令牌和浏览器是完全不同的话题,因为没有安全的地方可以存储刷新令牌。由于最近对第三方 cookie 浏览器的限制,使 Javascript 应用程序正常工作的唯一方法是将刷新令牌存储在本地存储中,从安全角度来看,这是灾难性的。

这个棘手问题的最佳解决方案是使用 API 驱动的解决方案,其中实用程序 API 为 SPA 发出 SameSite=strict cookie。不过,有一些移动部件可以部署到开发人员 PC 和您的管道中。有关设计模式的详细信息,请参阅下面的 Curity 资源。这也适用于 ADFS。