目录

Choosing the right flow

OpenIddict 为OAuth 2.0OpenID Connect核心 规范定义的所有标准流程提供内置支持 :授权代码流程隐式流程混合流程(基本上是前两个流程的混合)、 资源所有者password credentials grantclient credentials grant

虽然不是特定于 OpenIddict,但为您的应用程序选择最佳流程是 实现您自己的授权服务器的重要先决条件;下面是不同 OAuth 2.0/OpenID Connect 流程的快速概览:


非交互流程

直接受基本身份验证的启发,资源所有者密码凭据授予(缩写为ROPC)在概念上是最简单的 OAuth 2.0 流程:客户端应用程序询问用户他的用户名/密码,向授权服务器发送令牌请求和用户凭据(并取决于在授权服务器定义的客户端身份验证策略上,它自己的客户端凭据)并取回可用于检索用户资源的访问令牌。

资源所有者密码凭证流程

POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=johndoe&password=A3ddj3w
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"bearer",
  "expires_in":3600
}
警告

This flow is not recommended by the OAuth 2.0 specification as it's the only grant type where the user password is directly exposed to the client application, which breaks the principle of least privilege and makes it unsuitable for third-party client applications that can't be fully trusted by the authorization server.

While popular and trivial to implement (as it doesn't involve any redirection or consent form and unlike interactive flows, doesn't require implementing cross-site request forgery (XSRF) countermeasures to prevent session fixation attacks), its use in new applications is not recommended. Instead, users are encouraged to use the authorization code flow, that doesn't expose passwords to client applications and is not limited to password authentication.


The client credentials grant is almost identical to the resource owner password credentials grant, except it's been specifically designed for client-to-server scenarios (no user is involved in this flow): the client application sends a token request containing its credentials and gets back an access token it can use to query its own resources.

客户端凭据流

POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=s6BhdRkqt3&client_secret=gX1fBat3bV
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"bearer",
  "expires_in":3600
}
笔记

Unlike the resource owner password credentials grant, client authentication is not optional when using the client credentials grant and OpenIddict will always reject unauthenticated token requests, as required by the OAuth 2.0 specification.

This means that you CAN'T use the client credentials grant with public applications like browser, mobile or desktop applications, as they are not able to keep their credentials secret.


Interactive flows

While the authorization code flow is probably the most complicated flow (as it involves both user-agent redirections and backchannel communication), it's the recommended flow for any scenario involving end users, whether they log in using a password, a PIN, a smart card or even an external provider. In return for its complexity, this flow has a great advantage when used in server-side applications: the access_token cannot be intercepted by the user agent.

There are basically 2 steps in the authorization code flow: the authorization request/response and the token request/response.

授权码流程

  • Step 1: the authorization request

In this flow, the client application always initiates the authentication process by generating an authorization request including the mandatory response_type=code parameter, its client_id, its redirect_uri and optionally, a scope and a state parameter that allows flowing custom data and helps mitigate XSRF attacks.

笔记

In most cases, the client application will simply return a 302 response with a Location header to redirect the user agent to the authorization endpoint, but depending on the OpenID Connect client you're using, POST requests might also be supported to allow you to send large authorization requests. This feature is usually implemented using an auto-post HTML form.

HTTP/1.1 302 Found
Location: https://server.example.com/authorize?response_type=code&client_id=s6BhdRkqt3&state=af0ifjsldkj&redirect_uri=https://client.example.org/cb
GET /connect/authorize?response_type=code&client_id=s6BhdRkqt3&state=af0ifjsldkj&redirect_uri=https://client.example.org/cb HTTP/1.1
Host: server.example.com

The way the identity provider handles the authorization request is implementation-specific but in most cases, a consent form is displayed to ask the user if he or she agrees to share his/her personal data with the client application.

同意书

When the consent is given, the user agent is redirected back to the client application with a unique and short-lived token named authorization code that the client will be able to exchange with an access token by sending a token request.

HTTP/1.1 302 Found
Location: https://client.example.org/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj
警告

To prevent XSRF/session fixation attacks, the client application MUST ensure that the state parameter returned by the identity provider corresponds to the original state and stop processing the authorization response if the two values don't match. This is usually done by generating a non-guessable string and a corresponding correlation cookie.

  • Step 2: the token request

When the client application gets back an authorization code, it must immediately reedem it for an access token by sending a grant_type=authorization_code token request.

笔记

To help the identity provider mitigate counterfeit clients attacks, the original redirect_uri must also be sent.

If the client application is a confidential application (i.e an application that has been assigned client credentials), authentication is required.

POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&client_id=s6BhdRkqt3&client_secret=gX1fBat3bV&scope=openid
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"bearer",
  "expires_in":3600
}
笔记

To increase security, additional parameters such as code_challenge and code_challenge_method can be specified to bind the authorization code that will be returned by the authorization endpoint to the original authorization request. This mechanism is known as Proof Key for Code Exchange and is fully supported by OpenIddict.


The implicit flow is similar to the authorization code flow, except there's no token request/response step: the access token is directly returned to the client application as part of the authorization response in the URI fragment (or in the request form when using response_mode=form_post).

隐式流

GET /connect/authorize?response_type=token&client_id=s6BhdRkqt3&redirect_uri=https://client.example.org/cb&scope=openid&state=af0ifjsldkj&nonce=n-0S6_WzA2Mj HTTP/1.1
Host: server.example.com
HTTP/1.1 302 Found
Location: https://client.example.org/cb#access_token=SlAV32hkKG&token_type=bearer&expires_in=3600&state=af0ifjsldkj
警告

Initially designed for browser applications, this flow is inherently less secure than the authorization code flow and doesn't support Proof Key for Code Exchange. As such, using it in new applications is not recommended.

警告

为了防止 XSRF/会话固定攻击,客户端应用程序必须确保state身份提供者返回的参数与原始参数相对应state,如果两个值不匹配,则停止处理授权响应。 这通常是通过生成不可猜测的字符串和存储在本地存储中的相应值来完成的

使用隐式流时,客户端应用程序还必须确保访问令牌未颁发给另一个应用程序,以防止混淆代理攻击response_type=id_token token使用 OpenID Connect,这可以通过使用和检查audJWT 身份令牌的声明 来完成,该令牌必须对应或包含client_id客户端应用程序的。