OAuth 2.0 是授权领域的一个行业级标准协议,由 OAuth 发展而来,但不兼容前者。它所定义的授权流程,涵盖了 web、桌面、手机、电视等多种设备上的应用程序。

OAuth 2.0 授权类型概述

OAuth 2.0 是授权领域的一个行业级标准协议,由 OAuth 发展而来,但不兼容前者。它所定义的授权流程,涵盖了 web、桌面、手机、电视等多种设备上的应用程序。

概念

角色

  • 资源所有者 (resource owner)

能够授予对受保护资源的访问权的实体,即资源的拥有者。例如,终端用户

  • 资源服务器 (resource server)

寄宿受保护资源的服务器

  • 客户端 (client)

经过资源所有者的授权,代其请求受保护资源的应用程序

  • 授权服务器 (authorization server)

认证资源所有者并获得其授权后,向客户端签发访问令牌的服务器

令牌

  • 访问令牌 (access token)

用于访问受保护资源的凭证

  • 刷新令牌 (refresh token)

用于获取访问令牌的凭证

客户端类型

  • 机密客户端 (confidential client)

能够为其凭证保密的客户端,例如,在后台服务器上运行的应用

  • 公共客户端 (public client)

不能为其凭证保密的客户端,例如,在浏览器上运行的应用

需要注意,即使将凭证以二进制形式嵌入到移动应用程序中,这仍然被视作不保密

OAuth 2.0 协议流程

+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+

授权类型

资源所有者的密码凭证授权 (Resource Owner Password Credentials Grant)

+----------+
     | Resource |
     |  Owner   |
     |          |
     +----------+
          v
          |    Resource Owner
         (A) Password Credentials
          |
          v
     +---------+                                  +---------------+
     |         |>--(B)---- Resource Owner ------->|               |
     |         |         Password Credentials     | Authorization |
     | Client  |                                  |     Server    |
     |         |<--(C)---- Access Token ---------<|               |
     |         |    (w/ Optional Refresh Token)   |               |
     +---------+                                  +---------------+

! 由于向 client 暴露了密码凭证,存在很大的安全风险,已不被推荐使用

隐式授权 (Implicit Grant)

+----------+
     | Resource |
     |  Owner   |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier     +---------------+
     |         -+----(A)-- & Redirection URI --->|               |
     |  User-   |                                | Authorization |
     |  Agent  -|----(B)-- User authenticates -->|     Server    |
     |          |                                |               |
     |          |<---(C)--- Redirection URI ----<|               |
     |          |          with Access Token     +---------------+
     |          |            in Fragment
     |          |                                +---------------+
     |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
     |          |          without Fragment      |     Client    |
     |          |                                |    Resource   |
     |     (F)  |<---(E)------- Script ---------<|               |
     |          |                                +---------------+
     +-|--------+
       |    |
      (A)  (G) Access Token
       |    |
       ^    v
     +---------+
     |         |
     |  Client |
     |         |
     +---------+

隐式授权是为无服务器应用程序设计的,相比于验证码授权,它移除了交换验证码的步骤。但是,这种模式无法确认客户端收到了访问令牌,因此也不再被推荐使用

对于公共客户端(例如 native 应用和 javascript 应用),现在应当使用 PKCE 扩展的验证码授权流程

(A)客户端将用户导向认证服务器

(B)用户决定是否给于客户端授权

(C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌

(D)浏览器向 Web 托管的客户端资源发出请求,其中不包括上一步收到的Hash值

(E)Web 托管的客户端资源返回一个网页,其中包含的脚本代码可以获取Hash值中的令牌

(F)浏览器执行上一步获得的脚本,提取出令牌

(G)浏览器将令牌发给客户端

客户端凭证授权 (Client Credentials Grant)

+---------+                                  +---------------+
     |         |                                  |               |
     |         |>--(A)- Client Authentication --->| Authorization |
     | Client  |                                  |     Server    |
     |         |<--(B)---- Access Token ---------<|               |
     |         |                                  |               |
     +---------+                                  +---------------+

客户端凭证授权没有用户的参与,客户端本身就是资源所有者

授权码授权 (Authorization Code Grant)

+----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

授权码授权是应用最广泛的一种授权模式,

(A)用户访问客户端,后者将前者导向认证服务器

(B)用户选择是否给予客户端授权

(C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码

(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见

(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)

! 对于机密客户端,步骤 D 发起的请求,还携带有客户端密钥(client secret)

刷新令牌授权 (Refresh Token Grant)

+--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------+

出于安全性考虑,访问令牌仅在一段时间内有效

当旧的访问令牌过期时,客户端可以使用刷新令牌交换新的访问令牌,无需用户的参与

授权码交换验证密钥 (Proof Key for Code Exchange)

授权码劫持

+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
    | End Device (e.g., Smartphone)  |
    |                                |
    | +-------------+   +----------+ | (6) Access Token  +----------+
    | |Legitimate   |   | Malicious|<--------------------|          |
    | |OAuth 2.0 App|   | App      |-------------------->|          |
    | +-------------+   +----------+ | (5) Authorization |          |
    |        |    ^          ^       |        Grant      |          |
    |        |     \         |       |                   |          |
    |        |      \   (4)  |       |                   |          |
    |    (1) |       \  Authz|       |                   |          |
    |   Authz|        \ Code |       |                   |  Authz   |
    | Request|         \     |       |                   |  Server  |
    |        |          \    |       |                   |          |
    |        |           \   |       |                   |          |
    |        v            \  |       |                   |          |
    | +----------------------------+ |                   |          |
    | |                            | | (3) Authz Code    |          |
    | |     Operating System/      |<--------------------|          |
    | |         Browser            |-------------------->|          |
    | |                            | | (2) Authz Request |          |
    | +----------------------------+ |                   +----------+
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+

过程 1 是一个安全的 API 调用,过程 2 和 3 受 TLS 保护,但是恶意程序可以在过程 4 截获授权码

PKCE 协议流程

+-------------------+
                                                 |   Authz Server    |
       +--------+                                | +---------------+ |
       |        |--(A)- Authorization Request ---->|               | |
       |        |       + t(code_verifier), t_m  | | Authorization | |
       |        |                                | |    Endpoint   | |
       |        |<-(B)---- Authorization Code -----|               | |
       |        |                                | +---------------+ |
       | Client |                                |                   |
       |        |                                | +---------------+ |
       |        |--(C)-- Access Token Request ---->|               | |
       |        |          + code_verifier       | |    Token      | |
       |        |                                | |   Endpoint    | |
       |        |<-(D)------ Access Token ---------|               | |
       +--------+                                | +---------------+ |
                                                 +-------------------+

由于恶意程序没有 code_verifier ,所以即使拦截了授权码,也无法换取访问令牌

设备码授权 (Device Code Grant)

+----------+                                +----------------+
      |          |>---(A)-- Client Identifier --->|                |
      |          |                                |                |
      |          |<---(B)-- Device Code,      ---<|                |
      |          |          User Code,            |                |
      |  Device  |          & Verification URI    |                |
      |  Client  |                                |                |
      |          |  [polling]                     |                |
      |          |>---(E)-- Device Code       --->|                |
      |          |          & Client Identifier   |                |
      |          |                                |  Authorization |
      |          |<---(F)-- Access Token      ---<|     Server     |
      +----------+   (& Optional Refresh Token)   |                |
            v                                     |                |
            :                                     |                |
           (C) User Code & Verification URI       |                |
            :                                     |                |
            v                                     |                |
      +----------+                                |                |
      | End User |                                |                |
      |    at    |<---(D)-- End user reviews  --->|                |
      |  Browser |          authorization request |                |
      +----------+                                +----------------+

设备码授权主要用于无浏览器或者输入受限的设备。例如,用户可以使用手机扫描二维码,协助完成电视应用的授权