Formatting cleanup

This commit is contained in:
konarfil
2023-09-27 10:17:32 +02:00
parent 4b4687b899
commit 8aa2963d4f
17 changed files with 428 additions and 400 deletions

View File

@@ -234,6 +234,11 @@ pre {
text-align: center; text-align: center;
} }
.y-colored {
color: #FF6600 !important;
font-weight: bold;
}
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
.page-header { .page-header {
font-size: 1.5rem; font-size: 1.5rem;

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -56,25 +57,33 @@
<div class="card-stacked"> <div class="card-stacked">
<div class="card-content"> <div class="card-content">
<h6>2. Verify the state parameter</h6> <h6>2. Verify the state parameter</h6>
<p>You have now been redirected back to the application, to the page that was specified in the <b>redirect-url</b> parameter. In the URL you can notice, that there are addtional query parameters:</p> <p>
You have now been redirected back to the application, to the page that was specified in the <b>redirect-url</b> parameter.
In the URL you can notice, that there are addtional query parameters:
</p>
<pre class="code-block"><code id="queryParams"></code></pre> <pre class="code-block"><code id="queryParams"></code></pre>
<p>Let's break it down...</p> <p>Let's break it down...</p>
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">state</span>=<span id="state"></span></b></p> <p><b><span class="emphasis">state</span>=<span id="state"></span></b></p>
<p>The state parameter is an opaque value used by the client to maintain state between the request and the callback. <p>
Essentially, it is used to prevent Cross-Site Request Forgery (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF</a>) attacks and to ensure the response belongs to the request made by the client. The state parameter is an opaque value used by the client to maintain state between the request and the callback.
Essentially, it is used to prevent Cross-Site Request Forgery (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF</a>) attacks and to ensure the response belongs to the request made by the client.
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code</span>=<span id="code"></span></b></p> <p><b><span class="emphasis">code</span>=<span id="code"></span></b></p>
<p>The code parameter contains the actual authorization code. This is a temporary code that the client can exchange for an <p>
access token (and optionally, a refresh token) by making a back-channel request to the Authorization Server. The code parameter contains the actual authorization code. This is a temporary code that the client can exchange for an
The format and structure of the code is determined by the Authorization Server. It can be just a random string, or a more complex construction. The exact significance of this structure is specific to the Authorization Server implementation and might include different identifiers or information encoded in access token (and optionally, a refresh token) by making a back-channel request to the Authorization Server.
the structure.</p> The format and structure of the code is determined by the Authorization Server. It can be just a random string, or a more complex construction. The exact significance of this structure is specific to the Authorization Server implementation and might include different identifiers or information encoded in
the structure.
</p>
</li> </li>
</ul> </ul>
<p>Now we have everything necessary to obtain token for the user. But is the state we have sent (<b><span id="sent-state"></span></b>) equivalent to the one we received back (<b><span id="received-state"></span></b>)?</p> <p>
Now we have everything necessary to obtain token for the user. But is the state we have sent (<b><span id="sent-state"></span></b>) equivalent to the one we received back (<b><span id="received-state"></span></b>)?
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<div class="col m6 s12" style="margin-bottom: 5px;"> <div class="col m6 s12" style="margin-bottom: 5px;">
<a class="waves-effect waves-light btn btn-success full-width" onclick="proceedToNextStep()">States are matching</a> <a class="waves-effect waves-light btn btn-success full-width" onclick="proceedToNextStep()">States are matching</a>
@@ -117,4 +126,4 @@
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -72,9 +73,10 @@
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p> <p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p>
<p>Client ID of the application. This is a public identifier for the client, and it is <p>
used by the authorization server to identify the application Client ID of the application. This is a public identifier for the client, and it is
when redirecting the user back to the client.</p> used by the authorization server to identify the application when redirecting the user back to the client.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p> <p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p>
@@ -82,13 +84,11 @@
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code</span>=<span id="code"></span></b></p> <p><b><span class="emphasis">code</span>=<span id="code"></span></b></p>
<p>This is the authorization code we got in the previous step and is used to obtain the <p>This is the authorization code we got in the previous step and is used to obtain the access token.</p>
access token.</p>
</li> </li>
</ul> </ul>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="get-token-btn" class="waves-effect waves-light btn full-width" <a id="get-token-btn" class="waves-effect waves-light btn full-width" onClick="getToken()">Get access token</a>
onClick="getToken()">Get access token</a>
</div> </div>
</div> </div>
</div> </div>
@@ -106,43 +106,45 @@
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b>token_type</b></p> <p><b>token_type</b></p>
<p>Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever bears <p>
the token Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever bears
can access the resources.</p> the token can access the resources.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>expires_in</b></p> <p><b>expires_in</b></p>
<p>Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the access_token <p>
will expire and a Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the access_token
new one must be obtained.</p> will expire and a new one must be obtained.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>access_token</b></p> <p><b>access_token</b></p>
<p>This is the actual access token, which allows the client application to access the user's protected resources <p>
on the This is the actual access token, which allows the client application to access the user's protected resources
resource server (e.g., user profile, photos, etc.). on the resource server (e.g., user profile, photos, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>refresh_token</b></p> <p><b>refresh_token</b></p>
<p>Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a new <p>
<b>access_token</b> without Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a new
requiring the user to log in again. <b>access_token</b> without requiring the user to log in again.
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>scope</b></p> <p><b>scope</b></p>
<p>Specifies the scopes granted by the user to the client application. Scopes determine the permissions <p>
associated with the Specifies the scopes granted by the user to the client application. Scopes determine the permissions
<b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that with associated with the <b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that with
the provided access_token, the the provided access_token, the client application can access the user's email and profile information and is also granted offline access
client application can access the user's email and profile information and is also granted offline access (typically used in conjunction with refresh tokens).
(typically
used in conjunction with refresh tokens).
</p> </p>
</li> </li>
</ul> </ul>
<p>And this concludes the Authorization Code Flow. Client application would now be able to request resources on users behalf without having to transfer his credentials with each request.</p> <p>
And this concludes the Authorization Code Flow. Client application would now be able to request resources on users behalf without having to transfer his credentials with each request.
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a class="waves-effect waves-light btn full-width" href="/">Try different flow</a> <a class="waves-effect waves-light btn full-width" href="/">Try different flow</a>
</div> </div>
@@ -218,4 +220,4 @@
fillRequestExample(); fillRequestExample();
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -64,51 +65,60 @@
<p>Let's break it down...</p> <p>Let's break it down...</p>
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b><span id="baseUrl"></span></b> <p><b><span id="baseUrl"></span></b></p>
</p> <p>
<p>URL of the authorization endpoint on the server. How is this path constructed will URL of the authorization endpoint on the server. How is this path constructed will
differ between OAuth providers (such as Keycloak, Okta, etc.). differ between OAuth providers (such as Keycloak, Okta, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">response_type</span>=<span id="responseType"></span></b></p> <p><b><span class="emphasis">response_type</span>=<span id="responseType"></span></b></p>
<p>OAuth 2.0 response type. In this case, we are using the Authorization Code flow, so <p>
we are requesting the authorization <b>code</b>.</p> OAuth 2.0 response type. In this case, we are using the Authorization Code flow, so
we are requesting the authorization <b>code</b>.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p> <p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p>
<p>Client ID of the application. This is a public identifier for the client, and it is <p>
used by the authorization server to identify the application Client ID of the application. This is a public identifier for the client, and it is
when redirecting the user back to the client.</p> used by the authorization server to identify the application when redirecting the user back to the client.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p> <p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p>
<p>Redirect URI of the client. This is the URL that the authorization server will <p>
redirect the user back to after the user has logged in and Redirect URI of the client. This is the URL that the authorization server will
granted permissions. The redirect URI must match one of the URIs registered for the redirect the user back to after the user has logged in and granted permissions.
client ID.</p> The redirect URI must match one of the URIs registered for the client ID.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">scope</span>=<span id="scope"></span></b></p> <p><b><span class="emphasis">scope</span>=<span id="scope"></span></b></p>
<p>Scopes requested by the client. Scopes are used to limit the access of the access <p>
Scopes requested by the client. Scopes are used to limit the access of the access
token. In this case, we are requesting the <b>offline_access</b> scope, token. In this case, we are requesting the <b>offline_access</b> scope,
which allows the client to obtain a refresh token.</p> which allows the client to obtain a refresh token.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">state</span>=<span id="state"></span></b></p> <p><b><span class="emphasis">state</span>=<span id="state"></span></b></p>
<p>State parameter. This is an <b>optional parameter</b> that the client can use to maintain <p>
state between the request and callback. The authorization State parameter. This is an <b>optional parameter</b> that the client can use to maintain
server includes this parameter when redirecting the user back to the client, state between the request and callback. The authorization server includes this parameter when
allowing the client to verify that the response is coming from the redirecting the user back to the client, allowing the client to verify that the response is coming from the
server and not a malicious third party (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF attack</a>).</p> server and not a malicious third party (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF attack</a>).
</p>
</li> </li>
</ul> </ul>
<p>All that we now need to do is click the button below and login with our credentials. <p>
For the purposes of this All that we now need to do is click the button below and login with our credentials.
playground we already took the liberty to create <b>user</b> with password <b>user</b> for you. After your credentials are successfully verified, you will be redirected back to this playground, to the URL we have specified in the <b>redirect_uri</b> query parameter of the request.</p> For the purposes of this playground we already took the liberty to create <b>user</b> with password <b>user</b> for you.
After your credentials are successfully verified, you will be redirected back to this playground, to the URL we have specified in
the <b>redirect_uri</b> query parameter of the request.
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="sendRequestBtn" class="waves-effect waves-light btn full-width" <a id="sendRequestBtn" class="waves-effect waves-light btn full-width" href="#">Authenticate</a>
href="#">Authenticate</a>
</div> </div>
</div> </div>
</div> </div>
@@ -153,6 +163,8 @@
$("#redirectUri").text(redirectUri); $("#redirectUri").text(redirectUri);
$("#scope").text(scope); $("#scope").text(scope);
$("#state").text(state); $("#state").text(state);
$("#sendRequestBtn").attr("href", constructRequestUrl());
} }
function getRedirectUri() { function getRedirectUri() {
@@ -163,10 +175,9 @@
const redirectUri = getRedirectUri(); const redirectUri = getRedirectUri();
const scope = "offline_access"; const scope = "offline_access";
const state = generateSessionState(); const state = generateSessionState();
setCookie("state", state, 5); setCookie("state", state, 5);
fillExample(); fillExample();
$("#sendRequestBtn").attr("href", constructRequestUrl());
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,8 +12,7 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
@@ -20,6 +20,7 @@
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -73,21 +74,16 @@
<p><b><span class="emphasis">client_id</span>=<span id="client-id"></span></b></p> <p><b><span class="emphasis">client_id</span>=<span id="client-id"></span></b></p>
<p> <p>
Client ID of the application. This is a public identifier for the client, and it is Client ID of the application. This is a public identifier for the client, and it is
used by the authorization server to identify the application used by the authorization server to identify the application when redirecting the user back to the client.
when redirecting the user back to the client.
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">device_code</span>=<span id="device-code"></span></b></p> <p><b><span class="emphasis">device_code</span>=<span id="device-code"></span></b></p>
<p> <p>Device code we have obtained in the previous step.</p>
Device code we have obtained in the previous step.
</p>
</li> </li>
</ul> </ul>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="start-polling-btn" class="waves-effect waves-light btn full-width" <a id="start-polling-btn" class="waves-effect waves-light btn full-width" onclick="startPolling()">Start polling</a>
onclick="startPolling()">Start polling</a>
<div class="progress no-margin"> <div class="progress no-margin">
<div id="polling-bar" class="determinate" style="width: 0%"></div> <div id="polling-bar" class="determinate" style="width: 0%"></div>
</div> </div>
@@ -102,8 +98,9 @@
<div class="card-stacked"> <div class="card-stacked">
<div class="card-content"> <div class="card-content">
<h6>3. Instruct the user where to enter the code</h6> <h6>3. Instruct the user where to enter the code</h6>
<p>Device would typically show the user code on it's display (or in console output when connection to display-less device via SSH for example) and where possible, also the URL that the user should visit. Based on the capabilities the URL could be shown as a simple text, or QR code, or if the device didn't have display capable enough, than the URL could be written in a manual distributed with the device.</p> <p>
Device would typically show the user code on it's display (or in console output when connection to display-less device via SSH for example) and where possible, also the URL that the user should visit. Based on the capabilities the URL could be shown as a simple text, or QR code, or if the device didn't have display capable enough, than the URL could be written in a manual distributed with the device.
</p>
<div class="row col s12" style="margin-top: 15px;"> <div class="row col s12" style="margin-top: 15px;">
<div class="col m2 s0"></div> <div class="col m2 s0"></div>
<div class="col m3 s12" style="padding-top: 5px;"> <div class="col m3 s12" style="padding-top: 5px;">
@@ -113,12 +110,12 @@
<input id="user-code" type="text" disabled> <input id="user-code" type="text" disabled>
</div> </div>
<div class="col m2 s3" style="padding-top: 5px;"> <div class="col m2 s3" style="padding-top: 5px;">
<button title="Copy to clipboard" class="btn-floating waves-effect waves-light" style="background-color: #000000;" onclick="copyUserCodeToClipboard()"><i <button title="Copy to clipboard" class="btn-floating waves-effect waves-light" style="background-color: #000000;" onclick="copyUserCodeToClipboard()">
class="material-icons" style="font-size:18px;">content_copy</i></button> <i class="material-icons" style="font-size:18px;">content_copy</i>
</button>
</div> </div>
<div class="col m2 s0"></div> <div class="col m2 s0"></div>
</div> </div>
<p>Now that we have the user code, we can for example scan a QR code and finalize this flow on our mobile device:</p> <p>Now that we have the user code, we can for example scan a QR code and finalize this flow on our mobile device:</p>
<div class="row qr-container"> <div class="row qr-container">
<div id="qrcode" style="margin: 0 auto;"></div> <div id="qrcode" style="margin: 0 auto;"></div>
@@ -143,50 +140,46 @@
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b>token_type</b></p> <p><b>token_type</b></p>
<p>Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever <p>
bears Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever
the token bears the token can access the resources.
can access the resources.</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>expires_in</b></p> <p><b>expires_in</b></p>
<p>Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the <p>
access_token Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the
will expire and a access_token will expire and a new one must be obtained.
new one must be obtained.</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>access_token</b></p> <p><b>access_token</b></p>
<p>This is the actual access token, which allows the client application to access the user's protected <p>
resources This is the actual access token, which allows the client application to access the user's protected
on the resources on the resource server (e.g., user profile, photos, etc.).
resource server (e.g., user profile, photos, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>refresh_token</b></p> <p><b>refresh_token</b></p>
<p>Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a <p>
new Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a
<b>access_token</b> without new <b>access_token</b> without requiring the user to log in again.
requiring the user to log in again.
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>scope</b></p> <p><b>scope</b></p>
<p>Specifies the scopes granted by the user to the client application. Scopes determine the permissions <p>
associated with the Specifies the scopes granted by the user to the client application. Scopes determine the permissions
<b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that associated with the <b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that
with with the provided access_token, the client application can access the user's email and profile information and is also granted offline
the provided access_token, the access (typically used in conjunction with refresh tokens).
client application can access the user's email and profile information and is also granted offline
access
(typically
used in conjunction with refresh tokens).
</p> </p>
</li> </li>
</ul> </ul>
<p>And this concludes the Device Authorization Grant flow. Client application would now be able to request resources on <p>
users behalf without having to transfer his credentials with each request.</p> And this concludes the Device Authorization Grant flow. Client application would now be able to request resources on
users behalf without having to transfer his credentials with each request.
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a class="waves-effect waves-light btn full-width" href="/">Try different flow</a> <a class="waves-effect waves-light btn full-width" href="/">Try different flow</a>
</div> </div>
@@ -329,4 +322,4 @@
fillExample(); fillExample();
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -57,15 +58,14 @@
<div class="card-content"> <div class="card-content">
<h6>1. Request a Device Code</h6> <h6>1. Request a Device Code</h6>
<p> <p>
In order to initiate the <b>Device Authorization Grant</b>, we need to request a device code from the authorization server. The request is sent to the following URL: In order to initiate the <b>Device Authorization Grant</b>, we need to request a device code from the authorization server.
The request is sent to the following URL:
</p> </p>
<pre class="code-block"><code id="requestUriExample"></code></pre> <pre class="code-block"><code id="requestUriExample"></code></pre>
<p>With body data:</p> <p>With body data:</p>
<pre class="code-block"><code id="requestBodyExample"></code></pre> <pre class="code-block"><code id="requestBodyExample"></code></pre>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="get-code-btn" class="waves-effect waves-light btn full-width" <a id="get-code-btn" class="waves-effect waves-light btn full-width" onclick="getDeviceCode()">Get Device Code</a>
onclick="getDeviceCode()">Get Device Code</a>
</div> </div>
</div> </div>
</div> </div>
@@ -177,4 +177,4 @@
fillExample(); fillExample();
</script> </script>
</body> </body>
</html> </html>

View File

@@ -10,8 +10,7 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
@@ -31,8 +30,7 @@
Flow could not continue as it was missing vital information. This can be caused by not performing the flow before codes and/or cookies expire, or by manually navigating to section of a flow, before finishing previous steps. <b>Please start the flow again.</b> Flow could not continue as it was missing vital information. This can be caused by not performing the flow before codes and/or cookies expire, or by manually navigating to section of a flow, before finishing previous steps. <b>Please start the flow again.</b>
</p> </p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a class="waves-effect waves-light btn full-width" <a class="waves-effect waves-light btn full-width" href="/">Start over</a>
href="/">Start over</a>
</div> </div>
</div> </div>
</div> </div>
@@ -44,5 +42,4 @@
<footer class="page-footer"></footer> <footer class="page-footer"></footer>
<script src="../js/load-layout.js"></script> <script src="../js/load-layout.js"></script>
</body> </body>
</html> </html>

View File

@@ -11,8 +11,7 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
@@ -63,67 +62,78 @@
<div class="card-stacked"> <div class="card-stacked">
<div class="card-content"> <div class="card-content">
<h6>2. Build the Authorization URL</h6> <h6>2. Build the Authorization URL</h6>
<p> <p>First we need to build the authorization URL and redirect the user to the authorization server. The URL is constructed as follows:</p>
First we need to build the authorization URL and redirect the user to the authorization server. The URL is constructed as follows:
</p>
<pre class="code-block"><code id="requestUriExample"></code></pre> <pre class="code-block"><code id="requestUriExample"></code></pre>
<p>Let's break it down...</p> <p>Let's break it down...</p>
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b><span id="baseUrl"></span></b> <p><b><span id="baseUrl"></span></b></p>
</p> <p>
<p>URL of the authorization endpoint on the server. How is this path constructed will URL of the authorization endpoint on the server. How is this path constructed will
differ between OAuth providers (such as Keycloak, Okta, etc.). differ between OAuth providers (such as Keycloak, Okta, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">response_type</span>=<span id="responseType"></span></b></p> <p><b><span class="emphasis">response_type</span>=<span id="responseType"></span></b></p>
<p>OAuth 2.0 response type. In this case, we are using the Authorization Code flow, so <p>
we are requesting the authorization <b>code</b>.</p> OAuth 2.0 response type. In this case, we are using the Authorization Code flow, so
we are requesting the authorization <b>code</b>.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p> <p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p>
<p>Client ID of the application. This is a public identifier for the client, and it is <p>
Client ID of the application. This is a public identifier for the client, and it is
used by the authorization server to identify the application used by the authorization server to identify the application
when redirecting the user back to the client.</p> when redirecting the user back to the client.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p> <p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p>
<p>Redirect URI of the client. This is the URL that the authorization server will <p>
redirect the user back to after the user has logged in and Redirect URI of the client. This is the URL that the authorization server will
granted permissions. The redirect URI must match one of the URIs registered for the redirect the user back to after the user has logged in and granted permissions.
client ID.</p> The redirect URI must match one of the URIs registered for the client ID.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">scope</span>=<span id="scope"></span></b></p> <p><b><span class="emphasis">scope</span>=<span id="scope"></span></b></p>
<p>Scopes requested by the client. Scopes are used to limit the access of the access <p>
Scopes requested by the client. Scopes are used to limit the access of the access
token. In this case, we are requesting the <b>offline_access</b> scope, token. In this case, we are requesting the <b>offline_access</b> scope,
which allows the client to obtain a refresh token.</p> which allows the client to obtain a refresh token.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">state</span>=<span id="state"></span></b></p> <p><b><span class="emphasis">state</span>=<span id="state"></span></b></p>
<p>State parameter. This is an <b>optional parameter</b> that the client can use to maintain <p>
state between the request and callback. The authorization State parameter. This is an <b>optional parameter</b> that the client can use to maintain
server includes this parameter when redirecting the user back to the client, state between the request and callback. The authorization server includes this parameter when redirecting the
allowing the client to verify that the response is coming from the user back to the client, allowing the client to verify that the response is coming from the
server and not a malicious third party (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF attack</a>).</p> server and not a malicious third party (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF attack</a>).
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code_challenge</span>=<span id="codeChallenge"></span></b></p> <p><b><span class="emphasis">code_challenge</span>=<span id="codeChallenge"></span></b></p>
<p>This is the code challenge we have created in the previous step. This ensures that even if an attacker intercepts the authorization code, they can't exchange it for an access token without the original code verifier.</p> <p>
This is the code challenge we have created in the previous step. This ensures that even if an attacker intercepts the
authorization code, they can't exchange it for an access token without the original code verifier.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code_challenge_method</span>=<span id="codeChallengeMethod"></span></b></p> <p><b><span class="emphasis">code_challenge_method</span>=<span id="codeChallengeMethod"></span></b></p>
<p>Code Challenge method tells the identity provider how the <b>code_challenge</b> was generated from the original code verifier. <b>S256</b> means that <p>
the challenge is a base64url encoding of the SHA-256 hash of the verifier. This is the recommended method for PKCE.</p> Code Challenge method tells the identity provider how the <b>code_challenge</b> was generated from the original code
verifier. <b>S256</b> means that the challenge is a base64url encoding of the SHA-256 hash of the verifier. This is the recommended method for PKCE.
</p>
</li> </li>
</ul> </ul>
<p>All that we now need to do is click the button below and login with our credentials. <p>
For the purposes of this All that we now need to do is click the button below and login with our credentials. For the purposes of this playground we already
playground we already took the liberty to create <b>user</b> with password <b>user</b> for you. After your credentials are successfully verified, you will be redirected back to this playground, to the URL we have specified in the <b>redirect_uri</b> query parameter of the request.</p> took the liberty to create <b>user</b> with password <b>user</b> for you. After your credentials are successfully verified, you will be redirected back to this playground, to the URL we have specified in the <b>redirect_uri</b> query parameter of the request.
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="sendRequestBtn" class="waves-effect waves-light btn full-width" <a id="sendRequestBtn" class="waves-effect waves-light btn full-width" href="#">Authenticate</a>
href="#">Authenticate</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -63,34 +64,42 @@
<div class="card-stacked"> <div class="card-stacked">
<div class="card-content"> <div class="card-content">
<h6>3. Verify the state parameter</h6> <h6>3. Verify the state parameter</h6>
<p>You have now been redirected back to the application, to the page that was specified in the <b>redirect-url</b> parameter. In the URL you can notice, that there are addtional query parameters:</p> <p>
You have now been redirected back to the application, to the page that was specified in the <b>redirect-url</b> parameter. In the URL you can notice, that there are addtional query parameters:
</p>
<pre class="code-block"><code id="queryParams"></code></pre> <pre class="code-block"><code id="queryParams"></code></pre>
<p>Let's break it down...</p> <p>Let's break it down...</p>
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">state</span>=<span id="state"></span></b></p> <p><b><span class="emphasis">state</span>=<span id="state"></span></b></p>
<p>The state parameter is an opaque value used by the client to maintain state between the request and the callback. <p>
Essentially, it is used to prevent Cross-Site Request Forgery (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF</a>) attacks and to ensure the response belongs to the request made by the client. The state parameter is an opaque value used by the client to maintain state between the request and the callback.
<p>The state value isn't strictly necessary here since the PKCE parameters provide CSRF protection themselves. In practice, Essentially, it is used to prevent Cross-Site Request Forgery (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF</a>)
if you're sure the OAuth server supports PKCE, you can use the state parameter for application state instead of using it attacks and to ensure the response belongs to the request made by the client.
for CSRF protection.</p> </p>
</p> <p>
The state value isn't strictly necessary here since the PKCE parameters provide CSRF protection themselves. In practice,
if you're sure the OAuth server supports PKCE, you can use the state parameter for application state instead of using it
for CSRF protection.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code</span>=<span id="code"></span></b></p> <p><b><span class="emphasis">code</span>=<span id="code"></span></b></p>
<p>The code parameter contains the actual authorization code. This is a temporary code that the client can exchange for an <p>
access token (and optionally, a refresh token) by making a back-channel request to the Authorization Server. The code parameter contains the actual authorization code. This is a temporary code that the client can exchange for an
The format and structure of the code is determined by the Authorization Server. It can be just a random string, or a more complex construction. The exact significance of this structure is specific to the Authorization Server implementation and might include different identifiers or information encoded in access token (and optionally, a refresh token) by making a back-channel request to the Authorization Server.
the structure.</p> The format and structure of the code is determined by the Authorization Server. It can be just a random string, or a more complex construction. The exact significance of this structure is specific to the Authorization Server implementation and might include different identifiers or information encoded in
the structure.
</p>
</li> </li>
</ul> </ul>
<p>Now we have everything necessary to obtain token for the user. But is the state we have sent (<b><span <p>
id="sent-state"></span></b>) equivalent to the one we received back (<b><span Now we have everything necessary to obtain token for the user. But is the state we have sent (<b><span id="sent-state"></span></b>) equivalent to
id="received-state"></span></b>)?</p> the one we received back (<b><span id="received-state"></span></b>)?
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<div class="col m6 s12" style="margin-bottom: 5px;"> <div class="col m6 s12" style="margin-bottom: 5px;">
<a class="waves-effect waves-light btn btn-success full-width" onclick="proceedToNextStep()">States are <a class="waves-effect waves-light btn btn-success full-width" onclick="proceedToNextStep()">States are matching</a>
matching</a>
</div> </div>
<div class="col m6 s12"> <div class="col m6 s12">
<a class="waves-effect waves-light btn btn-error full-width" href="/flow/code">States are not matching</a> <a class="waves-effect waves-light btn btn-error full-width" href="/flow/code">States are not matching</a>
@@ -130,4 +139,4 @@
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -79,9 +80,10 @@
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p> <p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p>
<p>Client ID of the application. This is a public identifier for the client, and it is <p>
used by the authorization server to identify the application Client ID of the application. This is a public identifier for the client, and it is
when redirecting the user back to the client.</p> used by the authorization server to identify the application when redirecting the user back to the client.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p> <p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p>
@@ -89,20 +91,15 @@
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code</span>=<span id="code"></span></b></p> <p><b><span class="emphasis">code</span>=<span id="code"></span></b></p>
<p>This is the authorization code we got in the previous step and is used to obtain the <p>This is the authorization code we got in the previous step and is used to obtain the access token.</p>
access token.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code_verifier</span>=<span id="codeVerifier"></span></b></p> <p><b><span class="emphasis">code_verifier</span>=<span id="codeVerifier"></span></b></p>
<p>This is the code verifier we generated in the first step. It is used to verify the <p>This is the code verifier we generated in the first step. It is used to verify the identity of the client.</p>
identity of the client.
</p>
</li> </li>
</ul> </ul>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="get-token-btn" class="waves-effect waves-light btn full-width" <a id="get-token-btn" class="waves-effect waves-light btn full-width" onClick="getToken()">Get access token</a>
onClick="getToken()">Get access token</a>
</div> </div>
</div> </div>
</div> </div>
@@ -120,42 +117,46 @@
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b>token_type</b></p> <p><b>token_type</b></p>
<p>Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever bears <p>
the token Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever bears
can access the resources.</p> the token can access the resources.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>expires_in</b></p> <p><b>expires_in</b></p>
<p>Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the access_token <p>
will expire and a Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the access_token
new one must be obtained.</p> will expire and a new one must be obtained.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>access_token</b></p> <p><b>access_token</b></p>
<p>This is the actual access token, which allows the client application to access the user's protected resources <p>
on the This is the actual access token, which allows the client application to access the user's protected resources
resource server (e.g., user profile, photos, etc.). on the resource server (e.g., user profile, photos, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>refresh_token</b></p> <p><b>refresh_token</b></p>
<p>Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a new <p>
<b>access_token</b> without Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a new
requiring the user to log in again.</p> <b>access_token</b> without requiring the user to log in again.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>scope</b></p> <p><b>scope</b></p>
<p>Specifies the scopes granted by the user to the client application. Scopes determine the permissions <p>
associated with the Specifies the scopes granted by the user to the client application. Scopes determine the permissions
<b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that with associated with the <b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that with
the provided access_token, the the provided access_token, the client application can access the user's email and profile information and is also granted offline access
client application can access the user's email and profile information and is also granted offline access (typically used in conjunction with refresh tokens).
(typically
used in conjunction with refresh tokens).
</p> </p>
</li> </li>
</ul> </ul>
<p>And this concludes the Authorization Code Flow with PKCE. Client application would now be able to request resources on users behalf without having to transfer his credentials with each request.</p> <p>
And this concludes the Authorization Code Flow with PKCE. Client application would now be able to request resources on users behalf without
having to transfer his credentials with each request.
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a class="waves-effect waves-light btn full-width" href="/">Try different flow</a> <a class="waves-effect waves-light btn full-width" href="/">Try different flow</a>
</div> </div>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -10,14 +11,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -62,7 +63,9 @@
<div class="card-stacked"> <div class="card-stacked">
<div class="card-content"> <div class="card-content">
<h6>1. Create a Code Verifier and Challenge</h6> <h6>1. Create a Code Verifier and Challenge</h6>
<p>Before we can start the authorization process, we need to create a <b>code verifier</b> and a <b>code challenge</b>. The code verifier is a cryptographically random string that is used to verify the identity of the client. The code challenge is a hashed version of the code verifier, which is sent to the authorization server. The authorization server will then compare the code challenge with the code verifier to verify the identity of the client.</p> <p>
Before we can start the authorization process, we need to create a <b>code verifier</b> and a <b>code challenge</b>. The code verifier is a cryptographically random string that is used to verify the identity of the client. The code challenge is a hashed version of the code verifier, which is sent to the authorization server. The authorization server will then compare the code challenge with the code verifier to verify the identity of the client.
</p>
</p> </p>
<div class="row" style="margin-top: 20px;"> <div class="row" style="margin-top: 20px;">
<div class="col m3 s12"> <div class="col m3 s12">
@@ -72,9 +75,10 @@
<input id="codeVerifier" style="height: 30px;" type="text" disabled/> <input id="codeVerifier" style="height: 30px;" type="text" disabled/>
</div> </div>
</div> </div>
<p>
<p>Now that we habe the code verified, we need to create the code challenge. We do so by hashing the code verifier using the SHA256 algorithm and then encoding it using the URL-safe Base64 encoding.</p> Now that we habe the code verified, we need to create the code challenge. We do so by hashing the code verifier using the SHA256 algorithm and
then encoding it using the URL-safe Base64 encoding.
</p>
<div class="row" style="margin-top: 20px;"> <div class="row" style="margin-top: 20px;">
<div class="col m3 s12"> <div class="col m3 s12">
<div id="code-challenge-btn" class="waves-effect waves-light btn full-width disabled" onclick="generateCodeChallenge()">Generate Code Challenge</div> <div id="code-challenge-btn" class="waves-effect waves-light btn full-width disabled" onclick="generateCodeChallenge()">Generate Code Challenge</div>
@@ -83,12 +87,10 @@
<input id="codeChallenge" style="height: 30px;" type="text" disabled /> <input id="codeChallenge" style="height: 30px;" type="text" disabled />
</div> </div>
</div> </div>
<p>Now that we have the code verifier and code challenge, we can start the authorization process.</p> <p>Now that we have the code verifier and code challenge, we can start the authorization process.</p>
</p> </p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="continue-btn" class="waves-effect waves-light btn full-width disabled" <a id="continue-btn" class="waves-effect waves-light btn full-width disabled" href="/flow/pkce-2">Continue</a>
href="/flow/pkce-2">Continue</a>
</div> </div>
</div> </div>
</div> </div>
@@ -124,10 +126,7 @@
const verifier = $('#codeVerifier').val(); const verifier = $('#codeVerifier').val();
const encoder = new TextEncoder(); const encoder = new TextEncoder();
const data = encoder.encode(verifier); const data = encoder.encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', data); const digest = await crypto.subtle.digest('SHA-256', data);
// Convert hash to Base64 URL encoded string
const base64UrlEncoded = btoa(String.fromCharCode(...new Uint8Array(digest))) const base64UrlEncoded = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace('+', '-') .replace('+', '-')
.replace('/', '_') .replace('/', '_')
@@ -140,5 +139,4 @@
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -56,25 +57,34 @@
<div class="card-stacked"> <div class="card-stacked">
<div class="card-content"> <div class="card-content">
<h6>2. Verify the state parameter</h6> <h6>2. Verify the state parameter</h6>
<p>You have now been redirected back to the application, to the page that was specified in the <b>redirect-url</b> parameter. In the URL you can notice, that there are addtional query parameters:</p> <p>
You have now been redirected back to the application, to the page that was specified in the <b>redirect-url</b> parameter. In the URL
you can notice, that there are addtional query parameters:
</p>
<pre class="code-block"><code id="queryParams"></code></pre> <pre class="code-block"><code id="queryParams"></code></pre>
<p>Let's break it down...</p> <p>Let's break it down...</p>
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">state</span>=<span id="state"></span></b></p> <p><b><span class="emphasis">state</span>=<span id="state"></span></b></p>
<p>The state parameter is an opaque value used by the client to maintain state between the request and the callback. <p>
Essentially, it is used to prevent Cross-Site Request Forgery (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF</a>) attacks and to ensure the response belongs to the request made by the client. The state parameter is an opaque value used by the client to maintain state between the request and the callback.
</p> Essentially, it is used to prevent Cross-Site Request Forgery (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF</a>)
attacks and to ensure the response belongs to the request made by the client.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code</span>=<span id="code"></span></b></p> <p><b><span class="emphasis">code</span>=<span id="code"></span></b></p>
<p>The code parameter contains the actual authorization code. This is a temporary code that the client can exchange for an <p>
access token (and optionally, a refresh token) by making a back-channel request to the Authorization Server. The code parameter contains the actual authorization code. This is a temporary code that the client can exchange for an
The format and structure of the code is determined by the Authorization Server. It can be just a random string, or a more complex construction. The exact significance of this structure is specific to the Authorization Server implementation and might include different identifiers or information encoded in access token (and optionally, a refresh token) by making a back-channel request to the Authorization Server.
the structure.</p> The format and structure of the code is determined by the Authorization Server. It can be just a random string, or a more complex construction. The exact significance of this structure is specific to the Authorization Server implementation and might include different identifiers or information encoded in
the structure.
</p>
</li> </li>
</ul> </ul>
<p>Now we have everything necessary to obtain token for the user. But is the state we have sent (<b><span id="sent-state"></span></b>) equivalent to the one we received back (<b><span id="received-state"></span></b>)?</p> <p>
Now we have everything necessary to obtain token for the user. But is the state we have sent (<b><span id="sent-state"></span></b>) equivalent to the one we received back (<b><span id="received-state"></span></b>)?
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<div class="col m6 s12" style="margin-bottom: 5px;"> <div class="col m6 s12" style="margin-bottom: 5px;">
<a class="waves-effect waves-light btn btn-success full-width" onclick="proceedToNextStep()">States are matching</a> <a class="waves-effect waves-light btn btn-success full-width" onclick="proceedToNextStep()">States are matching</a>
@@ -117,4 +127,4 @@
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -11,14 +12,14 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="../js/analytics.js"></script> <script src="../js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"></header> <header id="page-header"></header>
<main> <main>
@@ -72,9 +73,10 @@
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p> <p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p>
<p>Client ID of the application. This is a public identifier for the client, and it is <p>
used by the authorization server to identify the application Client ID of the application. This is a public identifier for the client, and it is used by the authorization
when redirecting the user back to the client.</p> server to identify the application when redirecting the user back to the client.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p> <p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p>
@@ -82,13 +84,11 @@
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">code</span>=<span id="code"></span></b></p> <p><b><span class="emphasis">code</span>=<span id="code"></span></b></p>
<p>This is the authorization code we got in the previous step and is used to obtain the <p>This is the authorization code we got in the previous step and is used to obtain the access token.</p>
access token.</p>
</li> </li>
</ul> </ul>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="get-token-btn" class="waves-effect waves-light btn full-width" <a id="get-token-btn" class="waves-effect waves-light btn full-width" onClick="getToken()">Get access token</a>
onClick="getToken()">Get access token</a>
</div> </div>
</div> </div>
</div> </div>
@@ -106,43 +106,46 @@
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b>token_type</b></p> <p><b>token_type</b></p>
<p>Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever bears <p>
the token Indicates the type of token issued. In OAuth 2.0, the common type is "Bearer", which means that whoever bears
can access the resources.</p> the token can access the resources.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>expires_in</b></p> <p><b>expires_in</b></p>
<p>Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the access_token <p>
will expire and a Indicates the number of seconds for which the <b>access_token</b> is valid. After this time, the access_token
new one must be obtained.</p> will expire and a new one must be obtained.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>access_token</b></p> <p><b>access_token</b></p>
<p>This is the actual access token, which allows the client application to access the user's protected resources <p>
on the This is the actual access token, which allows the client application to access the user's protected resources
resource server (e.g., user profile, photos, etc.). on the resource server (e.g., user profile, photos, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>refresh_token</b></p> <p><b>refresh_token</b></p>
<p>Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a new <p>
<b>access_token</b> without Used to obtain a new <b>access_token</b> when the current one expires. This allows the client to get a new
requiring the user to log in again. <b>access_token</b> without requiring the user to log in again.
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b>scope</b></p> <p><b>scope</b></p>
<p>Specifies the scopes granted by the user to the client application. Scopes determine the permissions <p>
associated with the Specifies the scopes granted by the user to the client application. Scopes determine the permissions
<b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that with associated with the <b>access_token</b>. Here, the granted scopes are email, offline_access, and profile. This means that with
the provided access_token, the the provided access_token, the client application can access the user's email and profile information and is also granted offline access
client application can access the user's email and profile information and is also granted offline access (typically used in conjunction with refresh tokens).
(typically
used in conjunction with refresh tokens).
</p> </p>
</li> </li>
</ul> </ul>
<p>And this concludes the Authorization Code Flow. Client application would now be able to request resources on users behalf without having to transfer his credentials with each request.</p> <p>
And this concludes the Authorization Code Flow. Client application would now be able to request resources on users behalf
without having to transfer his credentials with each request.
</p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a class="waves-effect waves-light btn full-width" href="/">Try different flow</a> <a class="waves-effect waves-light btn full-width" href="/">Try different flow</a>
</div> </div>
@@ -218,4 +221,4 @@
fillRequestExample(); fillRequestExample();
</script> </script>
</body> </body>
</html> </html>

View File

@@ -12,8 +12,7 @@
<link type="text/css" rel="stylesheet" href="../css/style.css" /> <link type="text/css" rel="stylesheet" href="../css/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="stylesheet" <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;600;700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
@@ -60,71 +59,65 @@
<h6>1. Build the Authorization URL</h6> <h6>1. Build the Authorization URL</h6>
<p> <p>
In order to initiate the <b>WebAuthn</b>, we proceed the same way as we would if we would be using <b>Authorization Code Flow</b> we need to build the In order to initiate the <b>WebAuthn</b>, we proceed the same way as we would if we would be using <b>Authorization Code Flow</b> we need to build the
authorization URL authorization URL and redirect the user to the authorization server. All the passwordless logic is handled completely by the authorization server. The URL is constructed as follows:
and redirect the user to the authorization server. All the passwordless logic is handled completely by the authorization server. The URL is constructed as
follows:
</p> </p>
<pre class="code-block"><code id="requestUriExample"></code></pre> <pre class="code-block"><code id="requestUriExample"></code></pre>
<p>Let's break it down...</p> <p>Let's break it down...</p>
<ul class="collection"> <ul class="collection">
<li class="collection-item"> <li class="collection-item">
<p><b><span id="baseUrl"></span></b> <p><b><span id="baseUrl"></span></b></p>
</p> <p>
<p>URL of the authorization endpoint on the server. How is this path constructed URL of the authorization endpoint on the server. How is this path constructed
will will differ between OAuth providers (such as Keycloak, Okta, etc.).
differ between OAuth providers (such as Keycloak, Okta, etc.).
</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">response_type</span>=<span <p><b><span class="emphasis">response_type</span>=<span id="responseType"></span></b></p>
id="responseType"></span></b></p> <p>
<p>OAuth 2.0 response type. In this case, we are using the Authorization Code OAuth 2.0 response type. In this case, we are using the Authorization Code
flow, so flow, so we are requesting the authorization <b>code</b>.
we are requesting the authorization <b>code</b>.</p>
</li>
<li class="collection-item">
<p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b>
</p> </p>
<p>Client ID of the application. This is a public identifier for the client, and
it is
used by the authorization server to identify the application
when redirecting the user back to the client.</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span <p><b><span class="emphasis">client_id</span>=<span id="clientId"></span></b></p>
id="redirectUri"></span></b></p> <p>
<p>Redirect URI of the client. This is the URL that the authorization server Client ID of the application. This is a public identifier for the client, and
will it is used by the authorization server to identify the application when redirecting the user back to the client.
redirect the user back to after the user has logged in and </p>
</li>
<li class="collection-item">
<p><b><span class="emphasis">redirect_uri</span>=<span id="redirectUri"></span></b></p>
<p>
Redirect URI of the client. This is the URL that the authorization server
will redirect the user back to after the user has logged in and
granted permissions. The redirect URI must match one of the URIs registered granted permissions. The redirect URI must match one of the URIs registered
for the for the client ID.
client ID.</p> </p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">scope</span>=<span id="scope"></span></b></p> <p><b><span class="emphasis">scope</span>=<span id="scope"></span></b></p>
<p>Scopes requested by the client. Scopes are used to limit the access of the <p>
access Scopes requested by the client. Scopes are used to limit the access of the
token. In this case, we are requesting the <b>offline_access</b> scope, access token. In this case, we are requesting the <b>offline_access</b> scope,
which allows the client to obtain a refresh token.</p> which allows the client to obtain a refresh token.
</p>
</li> </li>
<li class="collection-item"> <li class="collection-item">
<p><b><span class="emphasis">state</span>=<span id="state"></span></b></p> <p><b><span class="emphasis">state</span>=<span id="state"></span></b></p>
<p>State parameter. This is an <b>optional parameter</b> that the client can use <p>
to maintain State parameter. This is an <b>optional parameter</b> that the client can use
state between the request and callback. The authorization to maintain state between the request and callback. The authorization
server includes this parameter when redirecting the user back to the client, server includes this parameter when redirecting the user back to the client,
allowing the client to verify that the response is coming from the allowing the client to verify that the response is coming from the
server and not a malicious third party (<a server and not a malicious third party (<a href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF attack</a>).
href="https://owasp.org/www-community/attacks/csrf" target="_blank">CSRF </p>
attack</a>).</p>
</li> </li>
</ul> </ul>
<p>All that we now need to do is click the button below and perform the <b>Web Authentication Flow</b> on the server. After your account will be successfully verified, you will be <p>
redirected back to this playground, to the URL we have specified in the All that we now need to do is click the button below and perform the <b>Web Authentication Flow</b> on the server. After your account will be successfully verified, you will be redirected back to this playground, to the URL we have specified in the <b>redirect_uri</b> query parameter of the request.
<b>redirect_uri</b> query parameter of the request.</p> </p>
<div class="row flow-submit-container"> <div class="row flow-submit-container">
<a id="sendRequestBtn" class="waves-effect waves-light btn full-width" <a id="sendRequestBtn" class="waves-effect waves-light btn full-width" href="#">Authenticate</a>
href="#">Authenticate</a>
</div> </div>
</div> </div>
</div> </div>
@@ -141,8 +134,6 @@
<script src="../js/cookies.js"></script> <script src="../js/cookies.js"></script>
<script src="../js/env-config.js"></script> <script src="../js/env-config.js"></script>
<script> <script>
const authUrl = baseUrl + "/passwordless"
function generateSessionState() { function generateSessionState() {
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
} }
@@ -171,12 +162,15 @@
$("#redirectUri").text(redirectUri); $("#redirectUri").text(redirectUri);
$("#scope").text(scope); $("#scope").text(scope);
$("#state").text(state); $("#state").text(state);
$("#sendRequestBtn").attr("href", constructRequestUrl());
} }
function getRedirectUri() { function getRedirectUri() {
return window.location.protocol + "//" + window.location.host + "/flow/webauthn-2"; return window.location.protocol + "//" + window.location.host + "/flow/webauthn-2";
} }
const authUrl = baseUrl + "/passwordless"
const responseType = "code"; const responseType = "code";
const redirectUri = getRedirectUri(); const redirectUri = getRedirectUri();
const scope = "offline_access"; const scope = "offline_access";
@@ -184,8 +178,6 @@
setCookie("webauth-state", state, 5); setCookie("webauth-state", state, 5);
fillExample(); fillExample();
$("#sendRequestBtn").attr("href", constructRequestUrl());
</script> </script>
</body> </body>
</html> </html>

View File

@@ -19,29 +19,28 @@
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
<script src="js/analytics.js"></script> <script src="js/analytics.js"></script>
</head> </head>
<body> <body>
<header id="page-header"> <header id="page-header"></header>
</header>
<main> <main>
<div class="container"> <div class="container">
<div class="section intro-section"> <div class="section intro-section">
<h3 class="header section-header">Welcome to OAuth 2.0 Playground</h3> <h3 class="header section-header">Welcome to OAuth 2.0 Playground</h3>
<p>This playground serves as an interactive platform designed to familiarize developers and students with the <p>
intricacies of OAuth authentication processes. Beyond just theoretical knowledge, this playground provides practical This playground serves as an interactive platform designed to familiarize developers and students with the
insights into the OAuth token exchange, intricacies of OAuth authentication processes. Beyond just theoretical knowledge, this playground provides practical
callback handling, and potential pitfalls or challenges one might face during real-world integrations. The ultimate aim insights into the OAuth token exchange,
is to bolster callback handling, and potential pitfalls or challenges one might face during real-world integrations. The ultimate aim
understanding and confidence in implementing OAuth, ensuring secure and efficient user authentication and authorization is to bolster
in modern web applications.</p> understanding and confidence in implementing OAuth, ensuring secure and efficient user authentication and authorization
in modern web applications.
</p>
<p>This project is an open-source initiative by Y Soft, as such we welcome any feedback or contributions at:</p> <p>This project is an open-source initiative by Y Soft, as such we welcome any feedback or contributions at:</p>
<ul class="list"> <ul class="list">
<li><b>Client side: </b><a <li><b>Client side: </b><a href="https://github.com/ysoftdevs/oauth-playground-client" target="_blank">ysoftdevs/oauth-playground-client</a></li>
href="https://github.com/ysoftdevs/oauth-playground-client" target="_blank">ysoftdevs/oauth-playground-client</a></li> <li><b>Server side: </b><a href="https://github.com/ysoftdevs/oauth-playground-server" target="_blank">ysoftdevs/oauth-playground-server</a></li>
<li><b>Server side: </b><a
href="https://github.com/ysoftdevs/oauth-playground-server" target="_blank">ysoftdevs/oauth-playground-server</a></li>
</ul> </ul>
</div> </div>
<div class="section"> <div class="section">
<h3 class="header section-header">Flows</h3> <h3 class="header section-header">Flows</h3>
<div class="divider" style="margin-bottom: 10px;"></div> <div class="divider" style="margin-bottom: 10px;"></div>
@@ -51,12 +50,14 @@
<div class="card-stacked flow-card"> <div class="card-stacked flow-card">
<div class="card-content"> <div class="card-content">
<h5>Authorization Code Flow</h5> <h5>Authorization Code Flow</h5>
<p class="justified">OAuth 2.0 protocol designed for web applications that can securely store client secrets. <p class="justified">
The application directs users to an authorization server to log in and grant permissions. Upon consent, the server OAuth 2.0 protocol designed for web applications that can securely store client secrets.
issues an authorization code. The application then exchanges this code for an access token in a server-to-server The application directs users to an authorization server to log in and grant permissions. Upon consent, the server
request, using its client ID, client secret, and redirection URI. This flow ensures the access token is never directly issues an authorization code. The application then exchanges this code for an access token in a server-to-server
exposed to users, offering enhanced security. It's best suited for server-side web applications with the capability to request, using its client ID, client secret, and redirection URI. This flow ensures the access token is never directly
protect the client secret.</p> exposed to users, offering enhanced security. It's best suited for server-side web applications with the capability to
protect the client secret.
</p>
</div> </div>
<div class="card-action"> <div class="card-action">
<a href="/flow/code">Try it</a> <a href="/flow/code">Try it</a>
@@ -69,12 +70,14 @@
<div class="card-stacked flow-card"> <div class="card-stacked flow-card">
<div class="card-content"> <div class="card-content">
<h5>PKCE</h5> <h5>PKCE</h5>
<p class="justified">Proof Key for Code Exchange is a security protocol for the OAuth 2.0 authorization framework, designed to prevent <p class="justified">
interception attacks in the authorization code flow. It's especially crucial for mobile or single-page applications Proof Key for Code Exchange is a security protocol for the OAuth 2.0 authorization framework, designed to prevent
where storing a client secret securely is challenging. In PKCE, the client creates a dynamic "code verifier" and its interception attacks in the authorization code flow. It's especially crucial for mobile or single-page applications
transformed "code challenge." The server remembers this challenge, and when the authorization code is exchanged for an where storing a client secret securely is challenging. In PKCE, the client creates a dynamic "code verifier" and its
access token, the client provides the original verifier. The server validates it against the stored challenge, ensuring transformed "code challenge." The server remembers this challenge, and when the authorization code is exchanged for an
added security against malicious interceptions.</p> access token, the client provides the original verifier. The server validates it against the stored challenge, ensuring
added security against malicious interceptions.
</p>
</div> </div>
<div class="card-action"> <div class="card-action">
<a href="/flow/pkce">Try it</a> <a href="/flow/pkce">Try it</a>
@@ -87,13 +90,15 @@
<div class="card-stacked flow-card"> <div class="card-stacked flow-card">
<div class="card-content"> <div class="card-content">
<h5>Device Authorization Grant</h5> <h5>Device Authorization Grant</h5>
<p class="justified">OAuth 2.0 flow optimized for devices that either lack a browser or have limited input <p class="justified">
capabilities, such as smart TVs, game consoles, and certain IoT devices. In this flow, the device makes a request to the OAuth 2.0 flow optimized for devices that either lack a browser or have limited input
authorization server and receives a unique user code and a verification URL. The user then accesses this URL on a capabilities, such as smart TVs, game consoles, and certain IoT devices. In this flow, the device makes a request to the
separate device with a browser, like a smartphone or computer, and enters the user code. After successfully logging in authorization server and receives a unique user code and a verification URL. The user then accesses this URL on a
and providing consent, the device polls the authorization server to obtain an access token. This method ensures a separate device with a browser, like a smartphone or computer, and enters the user code. After successfully logging in
streamlined user experience for devices with restricted input or display capabilities, allowing them to access protected and providing consent, the device polls the authorization server to obtain an access token. This method ensures a
resources without the need for intricate user interactions.</p> streamlined user experience for devices with restricted input or display capabilities, allowing them to access protected
resources without the need for intricate user interactions.
</p>
</div> </div>
<div class="card-action underConstruction"> <div class="card-action underConstruction">
<a href="/flow/dag">Try it</a> <a href="/flow/dag">Try it</a>
@@ -106,17 +111,14 @@
<div class="card-stacked flow-card"> <div class="card-stacked flow-card">
<div class="card-content"> <div class="card-content">
<h5>WebAuthn</h5> <h5>WebAuthn</h5>
<p class="justified">This protocol leverages public key cryptography and allows users to authenticate <p class="justified">
using biometrics, mobile devices, or This protocol leverages public key cryptography and allows users to authenticate using biometrics, mobile devices, or
FIDO security keys, instead of traditional passwords. When a user registers with a website, a unique FIDO security keys, instead of traditional passwords. When a user registers with a website, a unique key pair is
key pair is generated: the private key stays securely on the user's device, and the public key is registered with the website. For
generated: the private key stays securely on the user's device, and the public key is registered subsequent logins, the website challenges the user to prove ownership of the private key, typically by prompting for a
with the website. For biometric or a physical action on a security key. WebAuthn enhances user security by reducing reliance on easily
subsequent logins, the website challenges the user to prove ownership of the private key, typically compromised passwords and defending against phishing attacks.
by prompting for a </p>
biometric or a physical action on a security key. WebAuthn enhances user security by reducing
reliance on easily
compromised passwords and defending against phishing attacks.</p>
</div> </div>
<div class="card-action"> <div class="card-action">
<a href="/flow/webauthn">Try it</a> <a href="/flow/webauthn">Try it</a>
@@ -129,21 +131,15 @@
<div class="card-stacked flow-card"> <div class="card-stacked flow-card">
<div class="card-content"> <div class="card-content">
<h5>CIBA</h5> <h5>CIBA</h5>
<p class="justified">Client Initiated Backchannel Authentication is a protocol extension for OAuth 2.0, <p class="justified">
tailored for scenarios where Client Initiated Backchannel Authentication is a protocol extension for OAuth 2.0, tailored for scenarios where
the client, such as a financial institution or IoT device, initiates the authentication process the client, such as a financial institution or IoT device, initiates the authentication process without direct user
without direct user interaction on the client's platform. This is useful for "decoupled" authentication experiences, where, for instance, a
interaction on the client's platform. This is useful for "decoupled" authentication experiences, user might authenticate on their smartphone when prompted by a smart TV app. In CIBA, once the client requests
where, for instance, a authentication, the authorization server prompts the user on a previously registered device, such as their mobile phone.
user might authenticate on their smartphone when prompted by a smart TV app. In CIBA, once the Upon successful authentication, the authorization server sends a token back to the client. This flow provides a seamless
client requests and secure user experience, especially in contexts where traditional OAuth 2.0 interactions might be cumbersome or impractical.
authentication, the authorization server prompts the user on a previously registered device, such as </p>
their mobile phone.
Upon successful authentication, the authorization server sends a token back to the client. This flow
provides a seamless
and secure user experience, especially in contexts where traditional OAuth 2.0 interactions might be
cumbersome or
impractical.</p>
</div> </div>
<div class="card-action underConstruction"> <div class="card-action underConstruction">
<i class="tiny material-icons">build</i> Under construction <i class="tiny material-icons">build</i> Under construction
@@ -156,11 +152,13 @@
<div class="card-stacked flow-card"> <div class="card-stacked flow-card">
<div class="card-content"> <div class="card-content">
<h5>Implicit Flow</h5> <h5>Implicit Flow</h5>
<p class="justified">OAuth 2.0 Implicit Flow was designed for browser-based applications where the client cannot maintain the confidentiality <p class="justified">
of a secret. In this flow, after user authorization, the authorization server directly redirects the browser to the OAuth 2.0 Implicit Flow was designed for browser-based applications where the client cannot maintain the confidentiality
client application with an access token in the URL fragment. However, this can expose tokens in browser history or logs, of a secret. In this flow, after user authorization, the authorization server directly redirects the browser to the
making it less secure. Consequently, the use of Implicit Flow is being discouraged in favor of the more secure client application with an access token in the URL fragment. However, this can expose tokens in browser history or logs,
Authorization Code Flow with PKCE in recent OAuth specifications.</p> making it less secure. Consequently, the use of Implicit Flow is being discouraged in favor of the more secure
Authorization Code Flow with PKCE in recent OAuth specifications.
</p>
</div> </div>
<div class="card-action underConstruction"> <div class="card-action underConstruction">
<i class="tiny material-icons">build</i> Under construction <i class="tiny material-icons">build</i> Under construction
@@ -175,4 +173,4 @@
<footer class="page-footer"></footer> <footer class="page-footer"></footer>
<script src="js/load-layout.js"></script> <script src="js/load-layout.js"></script>
</body> </body>
</html> </html>

View File

@@ -4,27 +4,20 @@
<div class="row"> <div class="row">
<div class="col l6 s12"> <div class="col l6 s12">
<h5 class="white-text">OAuth 2.0 Playground</h5> <h5 class="white-text">OAuth 2.0 Playground</h5>
<p class="grey-text text-lighten-4">This playground serves as an interactive platform designed to <p class="grey-text text-lighten-4">
familiarize developers and students with the This playground serves as an interactive platform designed to familiarize developers and students with the
intricacies of OAuth authentication processes. Beyond just theoretical knowledge, this playground intricacies of OAuth authentication processes. Beyond just theoretical knowledge, this playground
provides practical insights into the OAuth token exchange, provides practical insights into the OAuth token exchange, callback handling, and potential pitfalls or challenges one
callback handling, and potential pitfalls or challenges one might face during real-world might face during real-world integrations. The ultimate aim is to bolster understanding and confidence in
integrations. The ultimate aim is to bolster implementing OAuth, ensuring secure and efficient user authentication and authorization in modern web applications.
understanding and confidence in implementing OAuth, ensuring secure and efficient user
authentication and authorization
in modern web applications.
</p> </p>
</div> </div>
<div class="col l4 offset-l2 s12"> <div class="col l4 offset-l2 s12">
<h5 class="white-text">Links</h5> <h5 class="white-text">Links</h5>
<ul> <ul>
<li><a class="grey-text text-lighten-3" href="https://www.oauth.com/" target="_blank">OAuth 2.0 <li><a class="grey-text text-lighten-3" href="https://www.oauth.com/" target="_blank">OAuth 2.0 Simplified</a></li>
Simplified</a></li> <li><a class="grey-text text-lighten-3" href="https://en.wikipedia.org/wiki/OAuth" target="_blank">OAuth Wikipedia</a></li>
<li><a class="grey-text text-lighten-3" href="https://en.wikipedia.org/wiki/OAuth" <li><a class="grey-text text-lighten-3" href="https://www.ietf.org/rfc/rfc6749.txt" target="_blank">OAuth 2.0 RFC</a></li>
target="_blank">OAuth
Wikipedia</a></li>
<li><a class="grey-text text-lighten-3" href="https://www.ietf.org/rfc/rfc6749.txt"
target="_blank">OAuth 2.0 RFC</a></li>
</ul> </ul>
</div> </div>
</div> </div>
@@ -32,13 +25,10 @@
<div class="footer-copyright"> <div class="footer-copyright">
<div class="container"> <div class="container">
© 2023 Y Soft Corporation ( © 2023 Y Soft Corporation (
<a class="grey-text text-lighten-4" style="color:#FF6600 !important; font-weight:bold;" <a class="y-colored" href="https://github.com/m0rsalis" target="_blank">m0rsalis</a> and
href="https://github.com/m0rsalis" target="_blank">m0rsalis</a> and <a class="y-colored" href="https://github.com/xRodney/" target="_blank">xRodney</a> )
<a class="grey-text text-lighten-4" style="color:#FF6600 !important; font-weight:bold;" <a class="y-colored right" href="https://www.daretothinkbyg.com" target="_blank">Join us today!</a>
href="https://github.com/xRodney/" target="_blank">xRodney</a> )
<a class="grey-text text-lighten-4 right" style="color:#FF6600 !important; font-weight:bold;"
href="https://www.daretothinkbyg.com" target="_blank">Join us today!</a>
</div> </div>
</div> </div>
</footer> </footer>
</div> </div>

View File

@@ -2,7 +2,7 @@
<div class="nav-wrapper page-header"> <div class="nav-wrapper page-header">
<a href="/" class=""> <a href="/" class="">
OAuth 2.0 Playground OAuth 2.0 Playground
<span style="font-size: 15px; color:#FF6600; font-weight:bold;">by Y Soft</span> <span class="y-colored" style="font-size: 15px;">by Y Soft</span>
</a> </a>
</div> </div>
</nav> </nav>