我的iOS移动应用程序使用实现了OAuth2.0协议的服务。OAuth访问令牌随附一个刷新令牌和一个expires_in
字段。我在应用程序中保存了刷新令牌和访问令牌过期时间,但不知道何时使用它们最好。
- 那么,通常和最佳实践是如何使用这个
expires_in
的呢? - 如何确定我的访问令牌已过期?
- 是否有一种常见的Web服务错误格式,可以说明我的访问令牌已过期?
以下是有关OAuth 2.0令牌刷新的信息。
OAuth 2.0标准RFC 6749将expires_in
字段定义为距离过期还有多少秒:
expires_in:建议使用。访问令牌的生命周期(以秒为单位)。例如,值“3600”表示访问令牌将在响应生成时的一小时后过期。如果未提供,则授权服务器应通过其他方式提供到期时间或记录默认值。
在接收到有效的access_token
、expires_in
值、refresh_token
等后,客户端可以通过存储到期时间并在每个请求时检查它来处理此问题。这可以通过以下步骤完成:
expires_in
转换为到期时间 (epoch, RFC-3339/ISO-8601 datetime等)access_token
已过期,则在资源请求之前进行令牌刷新请求一个示例实现是Go oauth2
库,它将expires_in
值转换为RFC 3339日期时间,并在Token的expiry
属性中。OAuth 2.0标准没有定义expiry
,但在这里很有用。
在检查时间时,请确保使用相同的时间,例如通过将所有时间转换为epoch或UTC时区来保持一致。
除了获得新的access_token
外,您可能会收到一个有效期更长的新的refresh_token
。如果收到此类信息,则应储存新的refresh_token
以延长会话的生命周期。
另一种处理令牌刷新的方法是在收到无效令牌授权错误后手动刷新。可以使用前面的方法或单独使用。
如果您尝试使用已过期的access_token
并且出现无效令牌错误,则应执行令牌刷新(如果您的刷新令牌仍然有效)。由于不同的服务可以使用不同的错误代码来表示过期的令牌,您可以为每个服务跟踪代码,或者在遇到4xx错误时简单地尝试单次刷新,这是跨服务刷新令牌的一种简单方法。
以下是一些流行服务的错误代码:
Zapier服务是一项实现授权错误重试后刷新的服务。
如果您的refresh_token
也已过期,则需要再次进行授权过程。
OAuth 2.0规范未定义刷新令牌的过期时间和处理方式,但许多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将返回具有静态时间的刷新令牌,因此如果一致地进行令牌刷新和更新,则用户无需再次进行身份验证。
推荐使用方法2,因为401错误可能由多种原因引起,例如更新令牌签名证书或时钟差异:
我已经实现了很多成功的OAuth客户端,并始终使用此技术-并避免在客户端代码中阅读expires_in字段。
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;
}
refresh_token
无效? :O - Nobitarefresh_token_expires_in
属性,我已经更新了答案并提供了这些信息。 - Grokify