如何识别 OAuth 令牌是不是已过期?

Posted

技术标签:

【中文标题】如何识别 OAuth 令牌是不是已过期?【英文标题】:How to identify if the OAuth token has expired?如何识别 OAuth 令牌是否已过期? 【发布时间】:2015-08-29 20:38:30 【问题描述】:

我的 ios 移动应用使用通过 OAuth2.0 协议实现的服务。 OAuth 访问令牌附带一个刷新令牌和一个expires_in 字段。我在我的应用中保存了刷新令牌和访问令牌过期时间,但不知道何时使用它们。

那么使用此expires_in 的通常和最佳做法是什么? 如何识别我的访问令牌已过期? 是否有一种常见的 Web 服务错误格式显示我的访问令牌已过期?

【问题讨论】:

【参考方案1】:

这是有关 OAuth 2.0 令牌刷新的信息。

定义过期

OAuth 2.0 标准 RFC 6749 将 expires_in 字段定义为到期秒数:

expires_in:推荐。访问令牌的生命周期(以秒为单位)。例如,值“3600”表示访问令牌将在响应生成后一小时内过期。如果省略,授权服务器应该通过其他方式提供过期时间或记录默认值。

令牌刷新处理:方法一

在收到有效的access_tokenexpires_in 值、refresh_token 等后,客户端可以通过存储过期时间并在每个请求上检查它来处理此问题。这可以通过以下步骤完成:

    expires_in 转换为过期时间(纪元、RFC-3339/ISO-8601 日期时间等) 存储过期时间 在每个资源请求上,检查当前时间与过期时间,如果access_token 已过期,则在资源请求之前发出令牌刷新请求

一个示例实现是 Go oauth2 库,它将 expires_in 值转换为令牌 expiry property 中的 RFC 3339 日期时间。 expiry 不是由 OAuth 2.0 标准定义的,但在这里很有用。

检查时间时,请确保您是同一时间,例如,通过将所有时间转换为纪元或 UTC 时区来使用相同的时区。

除了收到一个新的access_token 之外,您将来可能还会收到一个新的refresh_token,其到期时间会更长。如果您收到此邮件,您应该存储新的 refresh_token 以延长会话的生命周期。

令牌刷新处理:方法二

处理令牌刷新的另一种方法是在收到无效令牌授权错误后手动刷新。这可以通过以前的方法完成,也可以单独完成。

如果您尝试使用过期的access_token 并收到无效令牌错误,则应执行令牌刷新(如果您的刷新令牌仍然有效)。由于不同的服务可以对过期令牌使用不同的错误代码,因此您可以跟踪每个服务的代码,或者跨服务刷新令牌的简单方法是在遇到 4xx 错误时尝试一次刷新。

无效的访问令牌错误

以下是一些流行服务的错误代码:

    Facebook: Error 467 Invalid access token - 访问令牌已过期、被撤销或无效 - 处理过期的访问令牌。 LinkedIn: Error 401 Unauthorized。 PayPal: Error 401 Unauthorized。

实现

Zapier服务是一种实现授权错误重试后刷新的服务。

刷新令牌过期

如果您的refresh_token 也已过期,则需要重新进行授权。

OAuth 2.0 spec 没有定义刷新令牌过期或如何处理它,但是,当刷新令牌过期时,许多 API 将返回 refresh_token_expires_in 属性。不同的 API 会以不同的方式处理刷新令牌过期,因此查看每个 API 的文档很重要,但通常您在刷新访问令牌时可能会收到一个新的刷新令牌。过期应该以类似的方式处理,例如将 refresh_token_expires_in 转换为 RFC 3339 日期时间 refresh_token_expiry 值。

一些示例包括LinkedIn、eBay 和RingCentral。在 LinkedIn API 中,当您刷新访问令牌时,您将收到一个带有递减 refresh_token_expires_in 属性的刷新令牌,该属性以原始刷新令牌到期时间为目标,直到您需要再次进行身份验证。 RingCentral API 将返回具有静态时间的刷新令牌,因此如果令牌刷新和刷新令牌更新一致完成,用户不必再次进行身份验证。

【讨论】:

您好,非常感谢您的回复!在查看过期时间时,如果用户更改了设备时间怎么办?它不会导致过于频繁地刷新访问令牌吗?关于检查无效令牌错误,您对 oAuth 服务器将返回的响应代码和错误格式有什么想法吗?所有 oAuth 服务器的错误响应是否相同? 经常发生的设备时间变化有哪些用例?时区更改应自动处理。由于标准中没有定义无效令牌错误代码,因此不同的服务选择了上面列出的不同错误代码。如前所述,一种简单的刷新方法可能是在出现 4xx 错误时尝试单次刷新。 Spotify 未经授权返回 401 聚会迟到了,但是您怎么知道refresh_token 是否无效? :O IETF RFC 6749 没有定义刷新令牌过期或如何处理它,但是许多 API 实现了 refresh_token_expires_in 属性,我已经用这个信息更新了答案。【参考方案2】:

推荐上面的方法 2,因为 401 可能由于多种原因发生,例如更新令牌签名证书或时钟差异:

在每次 API 请求后检查 401 获取新令牌 - 仅一次 重试 API 请求 - 仅一次

我已经实现了许多成功的 OAuth 客户端并且一直使用这种技术 - 并且避免在我的客户端代码中读取 expires_in 字段

【讨论】:

我打算在我的应用程序中实现代码以检查 expires_in 字段,但在时区和用户更改设备时间方面遇到了很多问题。所以我将按照你上面所说的方式实现我的 NetworkingClient。 令牌发行者返回的过期时间不应该与用户时区无关吗?我希望它是 UTC。【参考方案3】:

该问题指定了 iOS,但作为任何工具集的一般原则,基于服务器的解决方案将令牌存储在服务器内存缓存中,并将缓存到期日期时间设置为与令牌的到期时间相同。

在需要身份验证令牌的任何其他端点之前调用以下函数。

这样它会从缓存中获取令牌,或者如果缓存过期(与令牌本身过期的时间相同)则获取新令牌。

对于 .NET:

    private async Task<string> GetAuthToken()
    
        string cacheKey = "AuthToken";

        if (!_memoryCache.TryGetValue(cacheKey, out string authToken))
        
            // Token not in cache, so get fresh one:

            // Do call for token
            HttpClient client = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, *url*);

            // Add Headers
            ...
            // Make call
            var response = await client.SendAsync(request);
            string responseContent = await response.Content.ReadAsStringAsync();

            // Check the call success/failure
            if (!response.IsSuccessStatusCode)
            
                return null;
            

            JObject authObj = JObject.Parse(responseContent);
            authToken = (string)authObj["access_token"];
            string authTokenExpires = (string)authObj["expires_in"];

            // Save data in cache.
            MemoryCacheEntryOptions staticDataCacheMemoryOptions = new MemoryCacheEntryOptions()
                    // Keep in cache until expired by Provider
                    .SetAbsoluteExpiration(DateTime.Now.AddSeconds(Convert.ToInt32(authTokenExpires)));

            _memoryCache.Set(cacheKey, authToken, staticDataCacheMemoryOptions);
        

        return authToken;
    

【讨论】:

以上是关于如何识别 OAuth 令牌是不是已过期?的主要内容,如果未能解决你的问题,请参考以下文章

OAuth 2.0 访问令牌已过期,刷新令牌不可用

google oauth2 刷新令牌何时过期?

如何检查密码重置令牌是不是已过期?

将大文件上传到服务器时,OAuth 访问令牌已过期

OAuth 2.0 刷新令牌是不是完全过期?

如何刷新OAuth2令牌?我是否需要等待令牌过期? (Patreon API)