澄清 id_token 与 access_token

Posted

技术标签:

【中文标题】澄清 id_token 与 access_token【英文标题】:Clarification on id_token vs access_token 【发布时间】:2018-03-22 18:07:22 【问题描述】:

我正在使用 OIDC 和 OAuth 2.0(使用 Auth0)构建一个系统,但我不确定如何正确使用 id_tokenaccess_token。或者更确切地说,我对在我的设置中为各种服务分配哪些角色感到困惑。

我有一个完全静态的前端应用程序(单页应用程序,html + JS,无后端),可确保使用针对 Auth0 的隐式流程对用户进行身份验证。然后前端应用程序从我也在构建的 API 中获取数据。

现在,哪个是正确的?

前端 SPA 是 OAuth 客户端应用程序 我的 API 服务是 OAuth 资源服务器

...或:

前端和我的 API 服务都是 客户端应用程序

如果我的前端和后端 API 都可以被视为客户端,我认为在从前端到后端的请求中使用 id_token 作为不记名令牌并没有真正的危害 - 这很有吸引力,因为这样我就可以简单地验证后端的签名令牌,我有我需要的用户的所有信息。但是,如果我的 API 被认为是 资源服务器,我可能应该使用 access_token,但是我必须在每个 API 请求上连接到 Auth0 的服务器以验证令牌并获取基本用户信息,不是吗?

我读过this,这似乎表明access_token 是与我的API 一起使用的唯一有效令牌。但就像我说的,我不确定各个服务的角色。并且使用id_token 很诱人,因为它不需要后端的网络连接,并且包含我需要提取正确数据的信息。

解决这个问题的正确方法是什么?

【问题讨论】:

我在 Auth0 论坛上得到了非常可靠的反馈:community.auth0.com/questions/10010/… 考虑将论坛回复转换为此处的答案,这将有助于我们其他人在同一条船上:-) 替代视图也是有效的,IMO。想象一下,您使用您的 Google 帐户登录您的应用程序。你得到一个 id_token 和一个 access_token。很明显,您使用 id_token 对您的应用进行身份验证,并使用 access_token 调用 Google API。 ID 令牌仅证明您已登录;它不允许您的应用代表您调用 Google API。另一方面,“你的应用”中的 API 服务没有被明确地单独授权为资源服务器——它们同样是“你的应用”的一部分,无论它们是通过 HTTP 还是本地方法调用访问 但规范明确指出必须验证 id_token:(openid.net/specs/openid-connect-implicit-1_0.html#ImplicitFlow) 2.1。隐式流** 6 Client validates the tokens and retrieves the End-User's Subject Identifier.** 简而言之:签名令牌的验证如何在前端发生? 【参考方案1】:

您的前端是您的 OAuth 客户端应用程序,一旦它存储了令牌,它就可以对 OAuth 流执行操作。而你的 API 服务是资源服务器,因为它接受你的身份服务器发出的 access_token。

另外我想说的是,您的 id_token 代表登录用户的标识,并且可能包含您应用的敏感数据。 access_token 是您访问资源的凭据。

最后,您将使用 access_token 请求资源,然后如果您需要登录用户(资源所有者)的特定数据,您可以从令牌端点请求 ID 令牌。

【讨论】:

【参考方案2】:

我喜欢这篇关于差异的 Medium 帖子,这一切都归功于这位作者。

https://medium.com/@nilasini/id-token-vs-access-token-17e7dd622084

如果您像我一样使用 Azure AD B2C,您可以在此处阅读更多信息:

https://docs.microsoft.com/en-us/azure/active-directory-b2c/openid-connect

ID 令牌

如果您使用范围作为 openid,您将获得 id 令牌。 Id 令牌特定于 openid 范围。使用 openid 范围,您可以获得 id 令牌和访问令牌。

OpenID Connect 对 OAuth 2.0 的主要扩展是 ID 令牌数据结构。 ID 令牌是一个安全令牌,它包含关于授权服务器在使用客户端时对最终用户进行身份验证的声明(声​​明是包含用户信息的名称/值对)以及可能的其他请求声明。 ID Token 表示为JSON Web Token (JWT)


   "iss": "https://server.example.com",
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "auth_time": 1311280969,
   "acr": "urn:mace:incommon:iap:silver"

以上是默认的 JWT 声明,除此之外,如果您向服务提供商请求声明,那么您也会得到这些声明。

根据 OIDC 规范,id_token 是 JWT。这意味着:

关于用户的身份信息被直接编码到令牌中 和 可以明确验证令牌以证明它没有被 被篡改。

规范中有一组rules 用于验证id_token。在id_token 中编码的声明中,有一个过期 (exp),它必须作为验证过程的一部分予以遵守。此外,JWT 的签名部分与密钥一起使用,以验证整个 JWT 未被以任何方式篡改。

访问令牌

访问令牌用作不记名令牌。不记名令牌意味着不记名(持有访问令牌)可以访问授权资源而无需进一步识别。因此,不记名令牌受到保护很重要。如果我能以某种方式获得并“持有”你的访问令牌,我就可以伪装成你。

为了提高安全性,这些令牌通常具有较短的生命周期(由其到期时间决定)。也就是说,当访问令牌过期时,用户必须再次进行身份验证以获取新的访问令牌,从而限制它是不记名令牌这一事实的暴露。

虽然 OIDC 规范没有强制要求,但 Okta 使用 JWT 访问令牌,因为(除其他外)到期时间直接内置于令牌中。

OIDC 指定一个 /userinfo 端点,该端点返回身份信息并且必须受到保护。提供访问令牌使端点可访问。

http://openid.net/specs/openid-connect-core-1_0.html https://connect2id.com/learn/openid-connect#cool-id-token-uses https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1

【讨论】:

【参考方案3】:

在我看来,第一种方法是正确的。您的 SPA 是客户端应用程序,您的 API 是资源服务器。

我建议您将 id_token 的使用限制在您的 SPA 之前。您可以使用 id 令牌中的基本信息(如用户名和电子邮件)在 UI 中显示用户信息。如果您也可以将访问令牌生成为 JWT,那么您的 API 可以验证访问令牌,而无需前往身份提供者。您可以在访问令牌中包含角色(或类似角色)以在访问令牌中获取授权信息。

【讨论】:

【参考方案4】:

我还想知道,如果我使用从 IdP 收到的令牌,是否需要在每个请求上都与 IdP 交谈。我最终得到了以下设置:

只有后端与 IdP 通信,前端不。 在 IdP 回调时,后端会为前端发出 JWT。 用户会话和前端-后端通信完全由我的应用使用 JWT 令牌管理。

查看这篇文章:OAuth2 in NestJS for Social Login (Google, Facebook, Twitter, etc)

这个仓库:https://github.com/thisismydesign/nestjs-starter

还有这个问题:OAuth2 flow in full-stack NestJS application

【讨论】:

【参考方案5】:

id_token 是用于身份验证的加密编码令牌。 OP(身份验证提供者)是生成它的那个,而 RP(依赖方或资源)最终会将令牌重新呈现给 OP,以在客户端移交令牌时进行反验证。简而言之,id_tokenauthn 工作流相关联。

access_token 启用资源访问。它确实包含用户信息,即id_token 或代表其请求访问的任何其他主体。因此,此令牌既包括用户声明,也包括对已授权组的声明。简而言之,access_token 与您的 authz 工作流程相关联。

【讨论】:

以上是关于澄清 id_token 与 access_token的主要内容,如果未能解决你的问题,请参考以下文章

谷歌 oauth2 id_token 与 refresh_token

WSO2隐式流不返回id_token

Azure AD:带有 PKCE 的代码流:没有为应用程序启用 id_token

使用 Keycloak 获取 id_token

在 ASP.NET Core API 中处理 id_token

如何使用 Spring 从 id_token 创建用户?