简体中文
  • invalid_grant
  • invalid grant error
  • oidc grant
  • oauth
  • auth
  • authentication

探索 OIDC 授权:理解和排查 "invalid_grant" 错误

学习 OpenID Connect(OIDC)授权的基本要素,并了解如何排查 "invalid_grant" 错误。

Charles
Charles
Developer

背景

在我们的社区中,我们经常听到用户反复提出的一个问题: Logto 中的 "invalid_grant" 错误是怎么回事?#503

这是我们的一些用户在将 Logto 集成到他们自己的应用程序时经常遇到的一个问题和阻碍。然而,这个错误背后的原因因情况而异,有时候在提供的上下文有限的情况下很难解释。因此,理解 OIDC 的确切概念并学习如何排查问题对每个人来说都是必要的。

现在让我们深入了解 OIDC 授权的基本概念。

OIDC 授权解释

如我们在之前的 博客文章 中介绍的,OpenID Connect (OIDC) 是建立在 OAuth 2.0 上的协议。

在 OIDC 或 OAuth2 的上下文中,授权 是资源所有者(通常是用户)给予客户端应用的一组权限。授权对于客户端应用来访问用户的身份信息和其他受保护的资源是必要的。OIDC 定义了几种授权类型,每种都适合不同的场景,以及应用获取访问令牌的方式。

以下是一个类比,帮助你更好地理解 OIDC 授权。

设想你正在不同的国家旅行,每个国家都要求入境签证章。在这种情况下,你的护照作为你的用户帐户,包含你的个人信息。OIDC 授权就像是你申请入境签证的方式。当你被发给签证时,你基本上获得了进入该国的 "令牌"。

同样,当你使用一个应用程序时,授权请求是你请求授权服务器给你访问权限的行动。授权服务器验证你的身份,并向你发放 "签证" (访问令牌),以登录到应用程序。

常用 OIDC 授权类型:

  1. Authorization Code Grant:这是 OIDC 中最常用的授权类型。它涉及将用户重定向到授权服务器,获取授权码,重定向回应用,然后用这个代码换取一个访问令牌。把它想象成在进入外国之前从大使馆申请签证的标准过程。
  2. Refresh Token Grant:在 OIDC 中,这种授权类型允许客户端应用使用之前发出的刷新令牌来获取新的访问令牌。它常常被用来在无需让用户重新输入其凭证的情况下延长用户的会话。想象你的签证带有一个魔术卡,可以让你在不再通过海关的情况下延长在外国的停留时间。
  3. Implicit Grant:这种授权类型用于旧的基于浏览器的应用,比 Authorization Code Grant 安全性较差。它直接将访问令牌返回给客户端应用。它就像 "落地签",因为不需要事先申请签证。
  4. Client Credentials Grant:适用于服务器到服务器通信,这种授权类型允许客户端应用使用其凭证(客户端 ID 和客户端 secret)直接与授权服务器进行身份验证。它就像特工展示特殊工作徽章,不用经过签证申请流程就能进入国家。

授权对象模型:

在 Logto 中,授权是以对象实体的形式持久化在数据库中的,包含了诸如用户帐户 ID,应用 ID,与 OIDC 资源和范围相关的信息,过期时间等等。每个刷新令牌和访问令牌都与一个特定的授权对象相关联。

授权请求:

如果你想通过从应用程序发送授权请求到 OIDC 令牌的 HTTP 请求。各种目的,包括为一个新的授权申请(比如登录并获取刷新和访问令牌),更新授权细节(例如,用一个刷新令牌换取一个新的访问令牌),或者撤销一个授权(例如,撤销发给已登录用户的所有令牌并终止他们的访问)。

一个典型的授权码授权请求如下所示:

理解 "invalid_grant" 错误

在 OIDC 中遇到 invalid_grant 错误通常表示授权类型或与授权请求相关的数据无效或不受支持。以下是这个错误背后的一些常见原因:

  1. 错误的授权类型:对于你的应用使用错误的授权类型可能会导致 invalid_grant 错误。请确保通过使用 Logto SDK 来使用适当的授权类型。
  2. 重定向 URI 不匹配:在交换授权码获取令牌时,请求中使用的重定向 URI 必须与初始授权请求中使用的 URI 相匹配。不匹配会导致 invalid_grant 错误。
  3. 授权码已过期或已被消费:在 Authorization Code 登录流程中,授权码的有效期有限,并且一旦用于获取令牌,就会被标记为 "已消费"。试图用过期或已消费的代码交换访问令牌将导致 invalid_grant 错误。
  4. 刷新令牌已过期或已旋转:在用刷新令牌换取访问令牌时,如果刷新令牌已经过期,invalid_grant 错误就会发生。此外,为了提高安全性,Logto 默认启用了 刷新令牌旋转。用同一个刷新令牌第二次请求令牌端点被视为使用了 "旋转" 的刷新令牌,将被拒绝。
  5. 缺少必要的数据或请求头:在组成授权请求时,必须为给定的授权类型提供必要的参数和请求头。例如,所有授权请求都必须提供客户端 ID,Client Credentials Grant 必须提供客户端 ID 和客户端密钥。这个风险也可以通过使用 Logto SDK 来减轻。
  6. 其他原因:这个错误还可能因为客户端凭证不匹配,授权过期或未找到,刷新令牌未找到等原因发生。

排查

一些有效排查 "invalid_grant" 错误的技巧:

  1. 总是使用 Logto 客户端 SDK 将 Logto 集成到你的应用程序,以确保授权请求被发送到相应的端点和正确的数据。
  2. 核实你的应用凭证和重定向 URI 与 Admin Console 中的配置是否匹配。
  3. 避免发送冗余请求,尤其是对于像 React 和 Vue 这样的 SPA,页面组件可能因为依赖性变化而重新渲染。确保用于交换代码或刷新令牌获取访问令牌的函数不会因为相同的请求参数而被多次触发。 这是我们一些用户常犯的一个错误。如果你在调试控制台看到多个 "token" 请求,第一个请求成功但之后的所有请求都失败,检查他们的请求参数,看看是否使用了相同的 "code" 或 "refresh token"。记住,你只能在授权请求中使用一次代码和刷新令牌。
  4. 检查过期时间。例如,如果你的刷新令牌已过期(默认为 14 天),并且你接收到 invalid_grant 错误,你应该通过再次初始化用户登录流程来正确处理它。如果你使用 Logto SDK,你可以再次调用signIn()函数,将用户重新定向回登录页面。
  5. 监控审计日志。去 Admin Console → 审计日志,找到与事故相关的错误日志,检查详细的错误堆栈跟踪。通常,在 invalid_grant 错误后面的堆栈跟踪中有一个更具体的原因,比如 "未找到授权" 或 "刷新令牌过期"。

结束语

invalid_grant 错误对初学者来说可能是具有挑战性和混淆性的,但是通过对 OIDC 授权的清晰理解和对细节的关注,你可以自己找出和解决问题。加入我们在 Discord 或 GitHub 的讨论,如果这篇博客有帮助你澄清混淆和找出你正在面临的问题,请告诉我们。Logto 开发团队始终乐于协助您。

让我们一起为你深爱的应用程序构建一个无缝且安全的身份验证体验。