mirror of
https://github.com/ysoftdevs/oauth-playground-client.git
synced 2026-01-17 17:22:07 +01:00
184 lines
10 KiB
HTML
184 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>OAuth 2.0 Playground - WebAuthn</title>
|
|
<meta name="description"
|
|
content="Step into the future of authentication with our WebAuthn guide. Experience firsthand how this web-based API redefines security, enabling passwordless and biometric verifications. Crucial for developers aiming to elevate user experience and protection in web apps." />
|
|
<link rel="icon" href="../favicon.ico" type="image/x-icon">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.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.gstatic.com" crossorigin />
|
|
<link rel="stylesheet" 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" />
|
|
<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 async src="https://www.googletagmanager.com/gtag/js?id=G-CVH4GP5T69"></script>
|
|
<script src="../js/analytics.js"></script>
|
|
</head>
|
|
|
|
<body>
|
|
<header id="page-header"></header>
|
|
<main>
|
|
<div class="container">
|
|
<div class="section">
|
|
<h3 class="header centered">WebAuthn</h3>
|
|
<div class="circle-container circle-3">
|
|
<div class="circle">
|
|
1
|
|
</div>
|
|
<div class="line line-inactive"></div>
|
|
<div class="circle circle-inactive">
|
|
2
|
|
</div>
|
|
<div class="line line-inactive"></div>
|
|
<div class="circle circle-inactive">
|
|
3
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col s4 circle-text">
|
|
Build the authorization URL and redirect the user to the authorization server
|
|
</div>
|
|
<div class="col s4 circle-text">
|
|
After the user is redirected back to the client, verify that the state matches
|
|
</div>
|
|
<div class="col s4 circle-text">
|
|
Exchange the authorization code for an access token
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section">
|
|
<div class="col s12 m7">
|
|
<div class="card horizontal">
|
|
<div class="card-stacked">
|
|
<div class="card-content">
|
|
<h6>1. Build the Authorization URL</h6>
|
|
<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
|
|
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:
|
|
</p>
|
|
<pre class="code-block"><code id="requestUriExample"></code></pre>
|
|
<p>Let's break it down...</p>
|
|
<ul class="collection">
|
|
<li class="collection-item">
|
|
<p><b><span id="baseUrl"></span></b></p>
|
|
<p>
|
|
URL of the authorization endpoint on the server. How is this path constructed
|
|
will differ between OAuth providers (such as Keycloak, Okta, etc.).
|
|
</p>
|
|
</li>
|
|
<li class="collection-item">
|
|
<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 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>
|
|
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 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
|
|
for the client ID.
|
|
</p>
|
|
</li>
|
|
<li class="collection-item">
|
|
<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
|
|
token. In this case, we are requesting the <b>offline_access</b> scope,
|
|
which allows the client to obtain a refresh token, <b>photos</b> to access photos
|
|
and <b>files</b> to have access to user files.
|
|
</p>
|
|
</li>
|
|
<li class="collection-item">
|
|
<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 state between the request and callback. The authorization
|
|
server includes this parameter when 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>
|
|
</li>
|
|
</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 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">
|
|
<a id="sendRequestBtn" class="waves-effect waves-light btn full-width" href="#">Authenticate</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section centered">
|
|
<a href="/">[ Take me home ]</a>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<footer class="page-footer"></footer>
|
|
<script src="../js/load-layout.js"></script>
|
|
<script src="../js/cookies.js"></script>
|
|
<script src="../js/env-config.js"></script>
|
|
<script>
|
|
function generateSessionState() {
|
|
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
|
}
|
|
|
|
function constructRequestUrl() {
|
|
return authUrl
|
|
+ "?" + "response_type=" + responseType
|
|
+ "&" + "client_id=" + getClientId()
|
|
+ "&" + "redirect_uri=" + redirectUri
|
|
+ "&" + "scope=" + scope
|
|
+ "&" + "state=" + state;
|
|
}
|
|
|
|
function fillExample() {
|
|
const requestExample = authUrl + "\n"
|
|
+ "?response_type=" + responseType + "\n"
|
|
+ "&client_id=" + getClientId() + "\n"
|
|
+ "&redirect_uri=" + redirectUri + "\n"
|
|
+ "&scope=" + scope + "\n"
|
|
+ "&state=" + state;
|
|
|
|
$("#requestUriExample").text(requestExample);
|
|
$("#baseUrl").text(authUrl);
|
|
$("#responseType").text(responseType);
|
|
$("#clientId").text(getClientId());
|
|
$("#redirectUri").text(redirectUri);
|
|
$("#scope").text(scope);
|
|
$("#state").text(state);
|
|
|
|
$("#sendRequestBtn").attr("href", constructRequestUrl());
|
|
}
|
|
|
|
function getRedirectUri() {
|
|
return window.location.protocol + "//" + window.location.host + "/flow/webauthn-2";
|
|
}
|
|
|
|
const authUrl = baseUrl + "/passwordless"
|
|
const responseType = "code";
|
|
const redirectUri = getRedirectUri();
|
|
const scope = "offline_access%20photos%20files";
|
|
const state = generateSessionState();
|
|
setCookie("webauth-state", state, 5);
|
|
|
|
fillExample();
|
|
</script>
|
|
</body>
|
|
</html> |