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

Posted

技术标签:

【中文标题】使用 AD FS 4.0 (2016) 或更高版本获取新的刷新令牌【英文标题】:Getting a new refresh token with AD FS 4.0 (2016) or higher 【发布时间】:2021-11-14 18:24:26 【问题描述】:

我将 AD FS 2016 配置为支持通过 OAuth2/OpenID Connect 使用授权代码授予和 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

...这给了我在 3 分钟后过期的访问/ID 令牌和在 7(实际上是 14,见下文)分钟后过期的刷新令牌。我还禁用了持久 SSO,所以我没有得到会话 cookie。都很好。

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

client_id:“我的客户” 代码:... redirect_uri: ... code_verifier: ... grant_type: "authorization_code"

我收到以下有效回复:


  "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 请求,这次使用以下参数:

刷新令牌:... grant_type: "refresh_token" client_id:“我的客户”

并返回如下成功响应:


  "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 在这件事上有些神秘:

虽然刷新令牌在用于获取新令牌时不会被撤销 访问令牌,您应该丢弃旧的刷新令牌。作为 根据 OAuth 2.0 规范:“授权服务器可能会发布一个新的 刷新令牌,在这种情况下客户端必须丢弃旧的刷新 令牌并将其替换为新的刷新令牌。授权 服务器可以在发出新的刷新后撤销旧的刷新令牌 令牌给客户端。” AD FS 在新的刷新时发出刷新令牌 令牌生命周期比之前的刷新令牌生命周期长。查看 有关 AD FS 刷新令牌生命周期的其他信息,请访问 AD FS 单点登录设置。

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

if (newRefreshTokenLifetime > previousRefreshTokenLifetime) 
  issueNewRefreshToken();

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

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

【问题讨论】:

【参考方案1】:

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

因此,如果用户在 09:00 登录 8 小时会话,并且他们的应用在 10:00 刷新访问令牌,那么如果发布了新的刷新令牌,则它应该可以使用 7 小时。也就是说,您不能在不再次涉及用户的情况下覆盖初始委托。

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

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

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

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

您有一个本机应用程序,其中标准解决方案始终是将刷新令牌存储在安全操作系统存储中,仅适用于应用程序和用户。刷新令牌是否旋转无关紧要。例子:

Desktop App ios App android App

SPA

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

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

Code Docs

【讨论】:

关键是 AD FS (v4.0) 似乎从未向您发送新的刷新令牌,即使当前的刷新令牌即将到期,但文档说应该... 您知道可用于 Windows Server 2019 的 AD FS 是否按预期运行?这仅仅是对 Windows Server 2016 可用的 AD FS 版本的限制吗? 2019 将表现相同 - 我的观点是你不应该依赖获取新的刷新令牌 - 因为根据 RFC6749 这不是标准的。我从来不知道任何 OAuth 系统可以在不涉及用户的情况下自动延长授权。这可能只是由于来自 Microsoft 的令人困惑的文档,其中所描述的行为不适用于代码流。这是否会导致您出现任何阻塞问题,或者仅仅是技术上的好奇? 它实际上导致了一些阻塞问题,因为我希望有一个带有 PKCE 流的授权代码也可以实现Refresh Token Rotation,既可以减少刷新令牌的生命周期,也可以保持用户在使用应用程序时进行身份验证。关于如何实现这一点的任何建议? 另外,根据 RFC6789,我不相信它不是标准的:“授权服务器可以发出一个新的刷新令牌,在这种情况下,客户端必须丢弃旧的刷新令牌并替换它使用新的刷新令牌。授权服务器可以在向客户端发出新的刷新令牌后撤销旧的刷新令牌。“根据标准,这不是强制性的,但它可以实现(这就是使刷新令牌轮换标准兼容的原因,我相信)。 根据您上次的编辑,您有点暗示刷新令牌的生命周期很长,即天/月。这对于原生应用程序来说通常是可以的,但是单页应用程序呢?我认为这是带有刷新令牌轮换的 PKCE 的主要用例。无论如何,我猜你回答了我的问题,现在无法使用 AD FS 进行配置。谢谢!

以上是关于使用 AD FS 4.0 (2016) 或更高版本获取新的刷新令牌的主要内容,如果未能解决你的问题,请参考以下文章

为 android 4.0 或更高版本创建自定义锁屏?

此版本的 Android Studio 无法打开此项目,请使用 Android Studio 4.0 或更高版本重试

检查 iOS 版本是不是与 PHP 兼容,从 iOS 3.0 到 IOS 4.0 或更高版本

由于 3.4.4 包不兼容,将 R 更新到 4.0 或更高版本?格维兹

使用 JavaScript 检测 iOS 5 或更高版本

已在此计算机上安装相同或更高版本的 .NET Framework 4