无论您使用哪种授权类型或是否使用客户端密码,您现在都拥有一个可与 API 一起使用的 OAuth 2.0 Bearer Token。
Authorization
访问令牌在以文本为前缀的HTTP 标头中发送到服务Bearer
。从历史上看,某些服务允许在 post 正文参数甚至 GET 查询字符串中发送令牌,但这些方法也有缺点,大多数现代实现将仅使用 HTTP 标头方法。
在 HTTP 标头中传递访问令牌时,您应该发出如下请求:
POST /resource/1/update HTTP/1.1
Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia"
Host: api.authorization-server.com
description=Hello+World
访问令牌不打算被您的应用程序解析或理解。你的应用程序唯一应该用它做的就是用它来发出 API 请求。某些服务将使用 JWT 等结构化令牌作为其访问令牌,如自编码访问令牌中所述,但在这种情况下,客户端无需担心解码令牌。
事实上,尝试解码访问令牌是危险的,因为服务器不保证访问令牌将始终保持相同的格式。下次您从该服务获取访问令牌时,完全有可能采用不同的格式。要记住的是,访问令牌对客户端是不透明的,应该只用于发出 API 请求而不是解释它们自己。
如果你想知道你的访问令牌是否已经过期,你可以存储你第一次获得访问令牌时返回的到期生命周期,或者只是尝试发出请求,如果当前一个已经过期了。实际上,没有太大区别。虽然先发制人地刷新访问令牌可以节省 HTTP 请求,但您仍然需要处理 API 调用在您预期令牌过期之前报告过期令牌的情况,因为访问令牌可能因许多超出预期寿命的原因而过期。
有关使用刷新令牌获取新访问令牌的更多详细信息,请参见下文。
如果您想了解有关登录用户的更多信息,您应该阅读特定服务的 API 文档以了解他们的建议。例如,Google 的 API 使用 OpenID Connect 提供一个 userinfo 端点,该端点可以返回有关给定访问令牌的用户的信息,或者您可以改为从 ID 令牌获取用户信息。我们在Signing in with Google中完成了 userinfo 端点工作流程的完整示例。
当您最初收到访问令牌时,它可能包含刷新令牌以及过期时间,如下例所示。
{
"access_token": "AYjcyMzY3ZDhiNmJkNTY",
"refresh_token": "RjY2NjM5NzA2OWJjuE7c",
"token_type": "bearer",
"expires": 3600
}
刷新令牌的存在意味着访问令牌将过期,您将能够在没有用户交互的情况下获得一个新令牌。
“expires_in”值是访问令牌有效的秒数。访问令牌的有效期取决于您使用的服务,并且可能取决于应用程序或组织自己的策略。您可以使用此时间戳来抢先刷新您的访问令牌,而不是等待带有过期令牌的请求失败。有些人喜欢在当前访问令牌到期前不久获得一个新的访问令牌,以保存 API 调用失败的 HTTP 请求。虽然这是一个非常好的优化,但它不会阻止您仍然需要处理如果访问令牌在预期时间之前过期时 API 调用失败的情况。访问令牌可能因多种原因而过期,例如用户撤销应用程序,或者如果授权服务器在用户更改密码时使所有令牌过期。
如果您发出 API 请求并且令牌已经过期,您将收到一个表明此情况的响应。您可以检查此特定错误消息,然后刷新令牌并再次尝试请求。
如果您使用的是基于 JSON 的 API,那么它可能会返回带有错误的 JSON 错误响应invalid_token
。在任何情况下,WWW-Authenticate
标头也会有invalid_token
错误代码。
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token"
error_description="The access token expired"
Content-type: application/json
{
"error": "invalid_token",
"error_description": "The access token expired"
}
当您的应用程序识别出此特定错误时,它可以使用之前收到的刷新令牌向令牌端点发出请求,并将取回可用于重试原始请求的新访问令牌。
要使用刷新令牌,请使用 向服务的令牌端点发出 POST 请求grant_type=refresh_token
,并在需要时包括刷新令牌和客户端凭据。
POST /oauth/token HTTP/1.1
Host: authorization-server.com
grant_type=refresh_token
&refresh_token=xxxxxxxxxxx
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx
响应将是一个新的访问令牌,并且可以选择一个新的刷新令牌,就像您在将授权代码交换为访问令牌时收到的一样。
{
"access_token": "BWjcyMzY3ZDhiNmJkNTY",
"refresh_token": "Srq2NjM5NzA2OWJjuE7c",
"token_type": "Bearer",
"expires": 3600
}
如果您没有取回新的刷新令牌,则意味着您现有的刷新令牌将在新访问令牌过期时继续工作。
最安全的选择是授权服务器在每次使用刷新令牌时发出一个新的刷新令牌。这是最新的安全最佳当前实践中的建议,它使授权服务器能够检测刷新令牌是否被盗。这对于没有客户端密钥的客户端尤其重要,因为刷新令牌成为获取新访问令牌所需的唯一东西。
当刷新令牌在每次使用后发生变化时,如果授权服务器检测到刷新令牌被使用了两次,则意味着它可能已被复制并被Attack者使用,授权服务器可以撤销所有访问令牌和相关的刷新令牌立即使用它。
请记住,用户可以随时撤销申请,因此您的应用程序需要能够处理使用刷新令牌也失败的情况。此时,您将需要再次提示用户进行授权,从头开始新的 OAuth 流程。
您可能会注意到“expires_in”属性指的是访问令牌,而不是刷新令牌。刷新令牌的到期时间有意从不传达给客户端。这是因为即使客户端能够知道刷新令牌何时过期,也无法采取任何可操作的步骤。刷新令牌也可能在其任何预期生命周期之前过期的原因有很多。
如果刷新令牌因任何原因过期,那么应用程序可以采取的唯一操作是要求用户重新登录,从头开始新的 OAuth 流程,这将向应用程序颁发新的访问令牌和刷新令牌。这就是应用程序是否知道刷新令牌的预期寿命无关紧要的原因,因为无论它过期的原因如何,结果总是相同的。