openiddict-documentation/guides/choosing-the-right-flow.html
2022-01-11 16:30:01 +00:00

259 lines
17 KiB
HTML

<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Choosing the right flow </title>
<meta name="viewport" content="width=device-width">
<meta name="title" content="Choosing the right flow ">
<meta name="generator" content="docfx 2.56.7.0">
<link rel="shortcut icon" href="../images/favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/night-owl.min.css">
<link rel="stylesheet" href="../styles/colors.css">
<link rel="stylesheet" href="../styles/discord.css">
<link rel="stylesheet" href="../styles/main.css">
<meta property="docfx:navrel" content="../toc.html">
<meta property="docfx:tocrel" content="toc.html">
</head>
<body>
<div class="top-navbar">
<a href="javascript:void(0);" class="burger-icon" onclick="toggleMenu()">
<svg name="Hamburger" style="vertical-align: middle;" width="24" height="24" viewbox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M20 6H4V9H20V6ZM4 10.999H20V13.999H4V10.999ZM4 15.999H20V18.999H4V15.999Z"></path></svg>
</a>
<a class="brand" href="../index.html">
<img src="../images/logo.png" alt="OpenIddict" class="logomark">
<span class="brand-title">OpenIddict</span>
</a>
</div>
<div class="body-content">
<div id="blackout" class="blackout" onclick="toggleMenu()"></div>
<nav id="sidebar" role="navigation">
<div class="sidebar">
<div>
<a class="brand" href="../index.html">
<img src="../images/logo.png" alt="OpenIddict" class="logomark">
<span class="brand-title">OpenIddict</span>
</a>
<div id="navbar">
</div>
</div>
<div class="sidebar-item-separator"></div>
<div id="sidetoggle">
<div id="sidetoc"></div>
</div>
</div>
<div class="footer">
<span>Generated by <strong>DocFX</strong></span>
</div>
</nav>
<main class="main-panel">
<div role="main" class="hide-when-search">
<div class="subnav navbar navbar-default">
<div class="container hide-when-search" id="breadcrumb">
<ul class="breadcrumb">
<li></li>
</ul>
</div>
</div>
<article class="content wrap" id="_content" data-uid="">
<h1 id="choosing-the-right-flow">Choosing the right flow</h1>
<p>OpenIddict offers built-in support for all the standard flows defined by the
<a href="https://tools.ietf.org/html/rfc6749">OAuth 2.0</a> and <a href="https://openid.net/specs/openid-connect-core-1_0.html">OpenID Connect</a> core specifications:
<a href="https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth">the authorization code flow</a>,
<a href="https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth">the implicit flow</a>,
<a href="https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth">the hybrid flow</a> (which is basically a mix between the first two flows),
<a href="https://tools.ietf.org/html/rfc6749#section-4.3">the resource owner password credentials grant</a> and
<a href="https://tools.ietf.org/html/rfc6749#section-4.4">the client credentials grant</a>.</p>
<p>While not specific to OpenIddict, choosing the best flow(s) for your application is an <strong>important prerequisite</strong>
when implementing your own authorization server ; so here&#39;s a quick overview of the different OAuth 2.0/OpenID Connect flows:</p>
<hr>
<h2 id="non-interactive-flows">Non-interactive flows</h2>
<h3 id="resource-owner-password-credentials-flow-not-recommended-for-new-applications">Resource owner password credentials flow (not recommended for new applications)</h3>
<p>Directly inspired by <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">basic authentication</a>, the resource owner password credentials grant
(abbreviated <em>ROPC</em>) is conceptually <strong>the simplest OAuth 2.0 flow</strong>: the client application asks the user his username/password, sends a token request
to the authorization server with the user credentials (and depending on the client authentication policy defined by the authorization server,
its own client credentials) and gets back an access token it can use to retrieve the user&#39;s resources.</p>
<p><img src="choosing-the-right-flow/resource-owner-password-flow.png" alt="Resource owner password credentials flow"></p>
<pre><code class="lang-http">POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&amp;username=johndoe&amp;password=A3ddj3w
</code></pre><pre><code class="lang-http">HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
&quot;access_token&quot;:&quot;2YotnFZFEjr1zCsicMWpAA&quot;,
&quot;token_type&quot;:&quot;bearer&quot;,
&quot;expires_in&quot;:3600
}
</code></pre><div class="CAUTION"><h5>Caution</h5><p>This flow is <strong>not recommended by the OAuth 2.0 specification</strong> as it&#39;s the only grant type where <strong>the user password is directly exposed to the client application</strong>,
which breaks the principle of least privilege and <strong>makes it unsuitable for third-party client applications that can&#39;t be fully trusted by the authorization server</strong>.</p>
<p>While popular and trivial to implement (as it doesn&#39;t involve any redirection or consent form and unlike interactive flows, doesn&#39;t require implementing
cross-site request forgery (XSRF) countermeasures to prevent session fixation attacks), <strong>its use in new applications is not recommended</strong>. Instead,
users are encouraged to use the authorization code flow, that doesn&#39;t expose passwords to client applications and is not limited to password authentication.</p>
</div>
<!-- more -->
<hr>
<h3 id="client-credentials-grant-recommended-for-machine-to-machine-communication">Client credentials grant (recommended for machine-to-machine communication)</h3>
<p>The client credentials grant is almost identical to the resource owner password credentials grant, except it&#39;s been specifically designed for <strong>client-to-server scenarios</strong>
(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.</p>
<p><img src="choosing-the-right-flow/client-credentials-flow.png" alt="Client credentials flow"></p>
<pre><code class="lang-http">POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&amp;client_id=s6BhdRkqt3&amp;client_secret=gX1fBat3bV
</code></pre><pre><code class="lang-http">HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
&quot;access_token&quot;:&quot;2YotnFZFEjr1zCsicMWpAA&quot;,
&quot;token_type&quot;:&quot;bearer&quot;,
&quot;expires_in&quot;:3600
}
</code></pre><div class="NOTE"><h5>Note</h5><p>Unlike the resource owner password credentials grant, <strong>client authentication is not optional</strong> when using the client credentials grant and
<strong>OpenIddict will always reject unauthenticated token requests</strong>, <a href="https://tools.ietf.org/html/rfc6749#section-4.4.2">as required by the OAuth 2.0 specification</a>.</p>
<p>This means that <strong>you CAN&#39;T use the client credentials grant with public applications</strong> like browser,
mobile or desktop applications, as they are not able to keep their credentials secret.</p>
</div>
<hr>
<h2 id="interactive-flows">Interactive flows</h2>
<h3 id="authorization-code-flow-recommended-for-new-applications">Authorization code flow (recommended for new applications)</h3>
<p>While the authorization code flow is probably the most complicated flow (as it involves both <strong>user-agent redirections and backchannel communication</strong>), it&#39;s
<strong>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</strong>.
In return for its complexity, this flow has a great advantage when used in server-side applications: the <code>access_token</code> cannot be intercepted by the user agent.</p>
<p>There are basically 2 steps in the authorization code flow: the authorization request/response and the token request/response.</p>
<p><img src="choosing-the-right-flow/authorization-code-flow.png" alt="Authorization code flow"></p>
<ul>
<li><strong>Step 1: the authorization request</strong></li>
</ul>
<p>In this flow, the client application always initiates the authentication process by generating an authorization request including
the mandatory <code>response_type=code</code> parameter, its <code>client_id</code>, its <code>redirect_uri</code> and optionally, a <code>scope</code> and a <code>state</code> parameter
<a href="https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest">that allows flowing custom data and helps mitigate XSRF attacks</a>.</p>
<div class="NOTE"><h5>Note</h5><p>In most cases, the client application will simply return a 302 response with a <code>Location</code> header to redirect the user agent to the authorization endpoint,
but depending on the OpenID Connect client you&#39;re using, POST requests might also be supported to allow you to send large authorization requests.
This feature <a href="https://github.com/aspnet/Security/pull/392">is usually implemented using an auto-post HTML form</a>.</p>
</div>
<pre><code class="lang-http">HTTP/1.1 302 Found
Location: https://server.example.com/authorize?response_type=code&amp;client_id=s6BhdRkqt3&amp;state=af0ifjsldkj&amp;redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
</code></pre><pre><code class="lang-http">GET /connect/authorize?response_type=code&amp;client_id=s6BhdRkqt3&amp;state=af0ifjsldkj&amp;redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com
</code></pre><p>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.</p>
<p><img src="choosing-the-right-flow/consent-form.png" alt="Consent form"></p>
<p>When the consent is given, the user agent is redirected back to the client application with <strong>a unique and short-lived token</strong>
named <em>authorization code</em> that the client will be able to exchange with an access token by sending a token request.</p>
<pre><code class="lang-http">HTTP/1.1 302 Found
Location: https://client.example.org/cb?code=SplxlOBeZQQYbYS6WxSbIA&amp;state=af0ifjsldkj
</code></pre><div class="WARNING"><h5>Warning</h5><p>To prevent XSRF/session fixation attacks, <strong>the client application MUST ensure that the <code>state</code> parameter returned by the identity provider
corresponds to the original <code>state</code></strong> and stop processing the authorization response if the two values don&#39;t match.
<a href="https://tools.ietf.org/html/rfc6749#section-10.12">This is usually done by generating a non-guessable string and a corresponding correlation cookie</a>.</p>
</div>
<ul>
<li><strong>Step 2: the token request</strong></li>
</ul>
<p>When the client application gets back an authorization code, it must immediately reedem it for an access token by sending a <code>grant_type=authorization_code</code> token request.</p>
<div class="NOTE"><h5>Note</h5><p>To help the identity provider <a href="https://tools.ietf.org/html/rfc6819#section-4.4.1.7">mitigate counterfeit clients attacks</a>, the original <code>redirect_uri</code> must also be sent.</p>
<p>If the client application is a confidential application (i.e an application that has been assigned client credentials), authentication is required.</p>
</div>
<pre><code class="lang-http">POST /connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&amp;code=SplxlOBeZQQYbYS6WxSbIA&amp;redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&amp;client_id=s6BhdRkqt3&amp;client_secret=gX1fBat3bV&amp;scope=openid
</code></pre><pre><code class="lang-http">HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
&quot;access_token&quot;:&quot;2YotnFZFEjr1zCsicMWpAA&quot;,
&quot;token_type&quot;:&quot;bearer&quot;,
&quot;expires_in&quot;:3600
}
</code></pre><div class="NOTE"><h5>Note</h5><p>To increase security, additional parameters such as <code>code_challenge</code> and <code>code_challenge_method</code> 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
<a href="../configuration/proof-key-for-code-exchange.html">Proof Key for Code Exchange</a> and is fully supported by OpenIddict. </p>
</div>
<hr>
<h3 id="implicit-flow-not-recommended-for-new-applications">Implicit flow (not recommended for new applications)</h3>
<p>The implicit flow is similar to the authorization code flow, <strong>except there&#39;s no token request/response step</strong>: 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 <code>response_mode=form_post</code>).</p>
<p><img src="choosing-the-right-flow/implicit-flow.png" alt="Implicit flow"></p>
<pre><code class="lang-http">GET /connect/authorize?response_type=token&amp;client_id=s6BhdRkqt3&amp;redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb&amp;scope=openid&amp;state=af0ifjsldkj&amp;nonce=n-0S6_WzA2Mj HTTP/1.1
Host: server.example.com
</code></pre><pre><code class="lang-http">HTTP/1.1 302 Found
Location: https://client.example.org/cb#access_token=SlAV32hkKG&amp;token_type=bearer&amp;expires_in=3600&amp;state=af0ifjsldkj
</code></pre><div class="CAUTION"><h5>Caution</h5><p>Initially designed for browser applications, this flow is inherently less secure than the authorization code flow and doesn&#39;t support
<a href="https://tools.ietf.org/html/rfc7636">Proof Key for Code Exchange</a>. As such, using it in new applications is not recommended.</p>
</div>
<div class="WARNING"><h5>Warning</h5><p>To prevent XSRF/session fixation attacks, <strong>the client application MUST ensure that the <code>state</code> parameter returned by the identity provider
corresponds to the original <code>state</code></strong> and stop processing the authorization response if the two values don&#39;t match.
<a href="https://tools.ietf.org/html/rfc6749#section-10.12">This is usually done by generating a non-guessable string and a corresponding value stored in the local storage</a>.</p>
<p>When using the implicit flow, <strong>the client application MUST also ensure that the access token was not issued
to another application to prevent <a href="https://stackoverflow.com/a/17439317/542757">confused deputy attacks</a>.</strong>
With OpenID Connect, this can be done by using <code>response_type=id_token token</code> and checking the <code>aud</code> claim
of the JWT identity token, that must correspond or contain the <code>client_id</code> of the client application.</p>
</div>
</article>
</div>
</main>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
<script type="text/javascript" src="../styles/jquery.twbsPagination.js"></script>
<script type="text/javascript" src="../styles/url.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
<script type="text/javascript" src="../styles/docfx.js"></script>
<script type="text/javascript" src="../styles/main.js"></script>
</body>
</html>