<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Michelle Marcelline</title>
    <description>The latest articles on Forem by Michelle Marcelline (@michelle).</description>
    <link>https://forem.com/michelle</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F412205%2Faeb8b8b6-2cee-420d-9891-a6f5233ac3ef.png</url>
      <title>Forem: Michelle Marcelline</title>
      <link>https://forem.com/michelle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/michelle"/>
    <language>en</language>
    <item>
      <title>OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI</title>
      <dc:creator>Michelle Marcelline</dc:creator>
      <pubDate>Tue, 04 Aug 2020 10:55:23 +0000</pubDate>
      <link>https://forem.com/cotter/oauth-2-0-before-you-start-pick-the-right-flow-for-your-website-spa-mobile-app-tv-app-and-cli-17n4</link>
      <guid>https://forem.com/cotter/oauth-2-0-before-you-start-pick-the-right-flow-for-your-website-spa-mobile-app-tv-app-and-cli-17n4</guid>
      <description>&lt;p&gt;&lt;em&gt;OAuth 2.0 has at least 4 different flows for different use cases. Find out which flow you should use to secure your app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2FCover.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2FCover.png" alt="OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We learned how OAuth 2.0 works in general in &lt;a href="https://dev.to/cotter/what-on-earth-is-oauth-a-super-simple-intro-to-oauth-2-0-access-tokens-and-how-to-implement-it-in-your-site-48jo"&gt;What on Earth is OAuth?&lt;/a&gt; and learned &lt;a href="https://dev.to/cotter/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end-15id"&gt;how to securely store access tokens in the front end.&lt;/a&gt; In this post, we'll learn which OAuth 2.0 flow you should use based on what you're building.&lt;/p&gt;

&lt;h1&gt;
  
  
  OAuth 2.0 Recap:
&lt;/h1&gt;

&lt;p&gt;In general, the OAuth 2.0 flow looks like this diagram below (if you're not familiar with the OAuth 2.0 Flow below, &lt;a href="https://dev.to/cotter/what-on-earth-is-oauth-a-super-simple-intro-to-oauth-2-0-access-tokens-and-how-to-implement-it-in-your-site-48jo"&gt;check our explanation here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-5.png" alt="OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI" width="800" height="400"&gt;&lt;/a&gt;OAuth 2.0 Flow with Google Sign In&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; The website requests authorization for Albert. Albert is being redirected to Google's site to log in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2:&lt;/strong&gt; Google's site returned with an &lt;strong&gt;Authorization Grant.&lt;/strong&gt;  &lt;strong&gt;This is the part that has several different cases based on which flow you're using.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3-4:&lt;/strong&gt; Depending on the flow, the client will have a way to exchange this &lt;strong&gt;Authorization Grant&lt;/strong&gt; with an access token, and sometimes a refresh token&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 5-6:&lt;/strong&gt; The website uses the access token to access resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Common OAuth 2.0 Flows
&lt;/h1&gt;

&lt;p&gt;As mentioned above, there are 4 common OAuth 2.0 Flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authorization Code Flow&lt;/li&gt;
&lt;li&gt;Authorization Code Flow with Proof Key for Code Exchange (PKCE)&lt;/li&gt;
&lt;li&gt;Client Credentials Flow&lt;/li&gt;
&lt;li&gt;Device Code Flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Which Flow Should I Use?
&lt;/h1&gt;

&lt;p&gt;Different apps should use different flows based on whether or not the app can hold secrets securely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web Server Apps and Command Line Scripts:&lt;/strong&gt; Use Authorization Code Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single Page Apps and Mobile Apps:&lt;/strong&gt; Use Authorization Code Flow with PKCE&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-to-Server API Calls&lt;/strong&gt; : Use Client Credentials Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TV Apps and other apps on input-constrained devices&lt;/strong&gt;: Use Device Code Flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Web Server Apps and Command Line Scripts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  → Use Authorization Code Flow
&lt;/h3&gt;

&lt;p&gt;Web Server Apps are apps that are running on a server where the source code is not publicly exposed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt; Your app needs to be able to hold a Client Secret securely in the back end server.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Your app runs on a server (Node.js, PHP, Java, .NET): Your server code is not publicly exposed and you can put secret keys in environment variables without it being visible to users of the application.&lt;/li&gt;
&lt;li&gt;❌ React-only website: React is a SPA framework, your code is publicly exposed, and therefore cannot hold secrets securely, even if you put secrets in .env files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authorization Code Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-1.png" alt="OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI" width="800" height="400"&gt;&lt;/a&gt;OAuth 2.0 Authorization Code Flow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1-4:&lt;/strong&gt; User clicks Sign in with Google, and get redirected to Google's Site to authenticate. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 5:&lt;/strong&gt; When the user successfully authenticated, Google will redirect the user back to your website, and include an &lt;code&gt;authorization_code&lt;/code&gt; in the redirect URL. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://mysite.com/redirect
    ?code=ABCDEFGHIJ12345
    &amp;amp;state=abcde123abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 6-9:&lt;/strong&gt;  With the code above and a Client ID + Client Secret that you get from Google when registering an application, you can request for an &lt;code&gt;access_token&lt;/code&gt; for the user that you can then use to fetch data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full spec at &lt;a href="https://tools.ietf.org/html/rfc6749#section-4.1" rel="noopener noreferrer"&gt;RFC 6749 Section 4.1&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I do this from the command line?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;step 3&lt;/strong&gt; , show the URL that the user should go to in their browser.&lt;/li&gt;
&lt;li&gt;Get your script to listen to a local port, for example, &lt;code&gt;http://127.0.0.1:8000&lt;/code&gt; and set the redirect URL to be &lt;code&gt;http://127.0.0.1:8000/redirect&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;On &lt;strong&gt;step 5&lt;/strong&gt; , the user's browser will redirect to
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://127.0.0.1:8000/redirect
    ?code=ABCDEFGHIJ12345
    &amp;amp;state=abcde123abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Your script should then handle this &lt;code&gt;GET&lt;/code&gt; request, parse the &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;state&lt;/code&gt; and proceed to step 6-9.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Single Page Apps &amp;amp; Mobile Apps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  → Use Authorization Code Flow with PKCE
&lt;/h3&gt;

&lt;p&gt;Single Page Apps (SPA) and Mobile Apps are not able to hold secrets securely because their source code is publicly exposed or can be decompiled.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does the PKCE flow work without a Client Secret?
&lt;/h3&gt;

&lt;p&gt;The PKCE flow requires the app to generate a secret on the fly. This secret is generated &lt;strong&gt;at the beginning of the flow&lt;/strong&gt; when the user started the login flow and then &lt;strong&gt;checked when exchanging authorization code with an access token.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This makes sure that the entity that is requesting to exchange the authorization code with an access token is still the same entity where the user requested to authenticate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorization Code Flow with PKCE
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-2.png" alt="OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI" width="800" height="400"&gt;&lt;/a&gt;OAuth 2.0 Authorization Code Flow with PKCE&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; User clicks the login button in your app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2:&lt;/strong&gt; Generate a &lt;code&gt;code_verifier&lt;/code&gt; and &lt;code&gt;code_challenge&lt;/code&gt;, then make an authorization request by sending the &lt;code&gt;code_challenge&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code_verifier = "a cryptographic random string"
code_challenge = base64url_encode(sha256(ascii(code_verifier)))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 3-5:&lt;/strong&gt; The Authorization Server will save the &lt;code&gt;code_challenge&lt;/code&gt; for later and redirect the user to log in, then redirect to your app with an &lt;code&gt;authorization_code&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 6&lt;/strong&gt; : Your app then sends the &lt;code&gt;code_verifier&lt;/code&gt; , &lt;code&gt;client_id&lt;/code&gt; , and &lt;code&gt;authorization_code&lt;/code&gt; to get an access token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 7:&lt;/strong&gt; The Authorization Server will check if the original &lt;code&gt;code_challenge == base64url_encode(sha256(ascii(code_verifier)))&lt;/code&gt;. This is where it determines whether the entity that started this flow is the same one as the one that is currently requesting an access token. If yes, it returns the access token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 8-9&lt;/strong&gt; : Your app can now fetch data using the access token.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full spec at &lt;a href="https://tools.ietf.org/html/rfc7636" rel="noopener noreferrer"&gt;RFC 7636&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are some resources to help you generate a code challenge and verifier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://example-app.com/pkce" rel="noopener noreferrer"&gt;Generate &lt;code&gt;code_verifier&lt;/code&gt; and &lt;code&gt;code_challenge&lt;/code&gt; online&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;See how to &lt;a href="https://docs.cotter.app/sdk-reference/api-for-other-mobile-apps/api-for-mobile-apps" rel="noopener noreferrer"&gt;generate &lt;code&gt;code_verifier&lt;/code&gt; and &lt;code&gt;code_challenge&lt;/code&gt; using JavaScript, Java, or Swift 3&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Server-to-Server API calls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  → Use Client Credentials Flow
&lt;/h3&gt;

&lt;p&gt;For example, your back end server wants to call an API endpoint at Stripe to retrieve a list of payments. This is a &lt;strong&gt;machine-to-machine authorization, and there's no end-user authorization.&lt;/strong&gt; In this case, Stripe is only trying to authorize your server to access the API endpoint. Since your server can also hold secrets securely, all you need for accessing the data is a &lt;strong&gt;Client ID and Client Secret&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Client Credentials Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-3.png" alt="OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI" width="800" height="400"&gt;&lt;/a&gt;OAuth 2.0 Client Credentials Flow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; Your server authenticates itself using its Client ID and Client Secret. Notice that this doesn't involve any user. This is because your server is acting as itself. (For example, your server is acting as &lt;strong&gt;Hello Merchant&lt;/strong&gt; that you registered to Stripe).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2:&lt;/strong&gt; If the Client ID and Client Secret checks out, you'll receive an access token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3:&lt;/strong&gt; Use the access token to fetch data. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full spec at &lt;a href="https://tools.ietf.org/html/rfc6749#section-4.4" rel="noopener noreferrer"&gt;RFC 6749 Section 4.4&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TV Apps and other apps on input-constrained devices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  → Use Device Code Flow
&lt;/h3&gt;

&lt;p&gt;It'll be horrible if you have to input your super-secure Google password to watch YouTube on your brand new smart TV, right? OAuth 2.0 Device Code Flow is designed so that you can authorize apps on an input constraint device &lt;strong&gt;by opening a URL and entering a code on your browser (on your phone/laptop).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements:&lt;/strong&gt; Your app needs to be able to display a URL and a User Code to the user. This can also be done by showing a QR Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Device Code Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F08%2Fimage-5.png" alt="OAuth 2.0 - Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1:&lt;/strong&gt; User requests to log in on your TV App.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2-3:&lt;/strong&gt; Your TV App makes an authorization request to the Authorization Server (Google Accounts in this case) with your app's Client ID, and receive 3 things: a &lt;code&gt;device_code&lt;/code&gt;, a &lt;code&gt;user_code&lt;/code&gt; , and a &lt;code&gt;verification_uri&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 4&lt;/strong&gt; : Your TV App now asks the user to go to the &lt;code&gt;verification_uri&lt;/code&gt; and enter the &lt;code&gt;user_code&lt;/code&gt; . You can optionally do this by asking the user to scan a QR Code that encodes both the &lt;code&gt;verification_uri&lt;/code&gt; and the &lt;code&gt;user_code&lt;/code&gt; .&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 5:&lt;/strong&gt; Your TV App now requests an access token to the Authorization Server using the &lt;code&gt;device_code&lt;/code&gt; and &lt;code&gt;client_id&lt;/code&gt; . If the user hasn't authenticated and allowed access to your app yet (they haven't gone to the &lt;code&gt;verification_uri&lt;/code&gt;), the Authorization Server will respond with an error &lt;code&gt;authorization_pending&lt;/code&gt;. Your TV App should keep on requesting until you get an access token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 6:&lt;/strong&gt; The user typed in the &lt;code&gt;verification_uri&lt;/code&gt; on their phone or laptop, and entered the &lt;code&gt;user_code&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 7-8:&lt;/strong&gt; The user is now redirected to Google's Login page where they can authenticate and allow your TV App to access certain data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 9&lt;/strong&gt; : Google accounts now mark that your user has authenticated and allowed your app to access their data. The next time your app requested for an access token with the &lt;code&gt;device_code&lt;/code&gt;, Google Accounts will return an access token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 10-11&lt;/strong&gt; : Use the access token to fetch data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the full spec at &lt;a href="https://tools.ietf.org/html/rfc8628#section-3.4" rel="noopener noreferrer"&gt;RFC 8628 Section 3.4&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's It!
&lt;/h2&gt;

&lt;p&gt;This should help you pick which OAuth 2.0 flow you need for different use cases. We didn't go into the specific HTTP Request parameters that you should use, we will cover that next time.&lt;/p&gt;

&lt;p&gt;This post is written by the team at &lt;a href="https://www.cotter.app/" rel="noopener noreferrer"&gt;Cotter&lt;/a&gt; – we are building lightweight, fast, and passwordless login solution for websites and mobile apps. If you're building a website, we have a ready-made solution that implements the flows above for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sign in with Magic Link via Email, SMS, or WhatsApp on:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.cotter.app/quickstart-guides/react-magic-link-with-email-and-phone" rel="noopener noreferrer"&gt;React.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cotter.app/sdk-reference/react-native/react-native-sdk-verify-email-phone" rel="noopener noreferrer"&gt;React Native&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cotter.app/sdk-reference/flutter/sign-in-with-email-phone-number" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;We referred to these articles and specs to write this post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tools.ietf.org/html/rfc6749#section-4" rel="noopener noreferrer"&gt;The OAuth 2.0 Authorization Framewor&lt;/a&gt;k (RFC 6749)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://oauth.net/2/grant-types/" rel="noopener noreferrer"&gt;OAuth Grant Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://alexbilbie.com/2016/04/oauth-2-device-flow-grant/" rel="noopener noreferrer"&gt;OAuth 2.0 Device Flow Grant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auth0.com/docs/flows" rel="noopener noreferrer"&gt;Authentication and Authorization Flows&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Questions &amp;amp; Feedback
&lt;/h3&gt;

&lt;p&gt;If you need help or have any feedback, ping us on &lt;a href="https://join.slack.com/t/askcotter/shared_invite/zt-dxzf311g-5Mp3~odZNB2DwYaxIJ1dJA" rel="noopener noreferrer"&gt;Cotter's Slack Channel&lt;/a&gt;! We're here to help.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ready to use Cotter?
&lt;/h3&gt;

&lt;p&gt;If you enjoyed this post and want to integrate Cotter into your website or app, you can &lt;a href="https://dev.cotter.app/" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; and &lt;a href="https://docs.cotter.app/" rel="noopener noreferrer"&gt;check out our documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>What is WebAuthn: Logging in with Face ID and Touch ID on the web</title>
      <dc:creator>Michelle Marcelline</dc:creator>
      <pubDate>Tue, 28 Jul 2020 07:13:42 +0000</pubDate>
      <link>https://forem.com/cotter/what-is-webauthn-logging-in-with-face-id-and-touch-id-on-the-web-4pm2</link>
      <guid>https://forem.com/cotter/what-is-webauthn-logging-in-with-face-id-and-touch-id-on-the-web-4pm2</guid>
      <description>&lt;p&gt;&lt;em&gt;Enable TouchID and Windows Hello authentication to your website. Introducing WebAuthn: how it works and how to implement it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FCover-4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FCover-4.png" alt="What is WebAuthn: Logging in with Face ID and Touch ID on the web" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is WebAuthn?
&lt;/h3&gt;

&lt;p&gt;The Web Authentication API is an authentication &lt;a href="https://w3c.github.io/webauthn/" rel="noopener noreferrer"&gt;specification&lt;/a&gt; that allows Websites to authenticate users with built-in authenticators like Apple's TouchID and Windows Hello, or using security keys like Yubikey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-11.png" alt="What is WebAuthn: Logging in with Face ID and Touch ID on the web" width="800" height="400"&gt;&lt;/a&gt;WebAuthn Login with Cotter&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It utilizes public-key cryptography instead of passwords&lt;/strong&gt;. When the user registers, a private-public key pair is generated for the account, and the private key is stored securely in the user's device, while the public key is sent to the server. The server can then ask the user's device to sign a challenge using the private key to authenticate the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registration with WebAuthn
&lt;/h3&gt;

&lt;p&gt;Usually, a website will ask the user to enter a username and password. With WebAuthn, the website will generate this public-private key pair and send the public key to the server and store the private key securely in the user's device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FRegistration-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FRegistration-2.png" alt="What is WebAuthn: Logging in with Face ID and Touch ID on the web" width="800" height="400"&gt;&lt;/a&gt;WebAuthn Registration Flow&lt;/p&gt;

&lt;h3&gt;
  
  
  Logging-in with WebAuthn
&lt;/h3&gt;

&lt;p&gt;This is where websites usually check whether the user has provided the right username and password. With WebAuthn, the website will send a challenge and check if the browser can sign the challenge using the private key that's stored in the user's device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FLogin-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FLogin-3.png" alt="What is WebAuthn: Logging in with Face ID and Touch ID on the web" width="800" height="400"&gt;&lt;/a&gt;WebAuthn Login Flow&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;We've built a simple way to implement WebAuthn using Cotter that you can do in just a few minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try WebAuthn in Action.
&lt;/h3&gt;

&lt;p&gt;We've made a simple site for you to try it out: &lt;a href="https://cotter.herokuapp.com/" rel="noopener noreferrer"&gt;https://cotter.herokuapp.com/&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you're using &lt;strong&gt;Google Chrome&lt;/strong&gt; on a laptop that supports TouchID/Windows Hello.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registration:&lt;/strong&gt; If this is your first time logging in, you'll be prompted to enable TouchID or Windows Hello after your email is verified.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login:&lt;/strong&gt; Go to an &lt;strong&gt;incognito tab&lt;/strong&gt; and open this URL again. You need to &lt;strong&gt;allow third-party cookies&lt;/strong&gt; (eye icon on URL bar). Try logging in with the same email, and you'll be prompted to log in using WebAuthn.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Short Guide for Implementing WebAuthn with React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add cotter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Implement Login with WebAuthn
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Import Cotter&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;signInWithWebAuthnOrLink&lt;/code&gt; to use WebAuthn with Magic Link as the fallback method, followed by &lt;code&gt;showEmailForm&lt;/code&gt; or &lt;code&gt;showPhoneForm&lt;/code&gt;, and get the response as a promise.&lt;/li&gt;
&lt;li&gt;Setup a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with &lt;code&gt;id="cotter-form-container"&lt;/code&gt; that will contain the form.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Cotter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cotter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1️⃣ Import Cotter&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setpayload&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// 2️⃣ Initialize and show the form&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cotter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cotter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;API_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 👈 Specify your API KEY ID here&lt;/span&gt;
    &lt;span class="nx"&gt;cotter&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithWebAuthnOrLink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// 👈 sign in using WebAuthn&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showEmailForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setpayload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// show the response in our state&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* 3️⃣ Put a &amp;lt;div&amp;gt; that will contain the form */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"cotter-form-container"&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
App.js





&lt;p&gt;​You'll need an &lt;code&gt;API_KEY_ID&lt;/code&gt; , &lt;a href="https://dev.cotter.app/" rel="noopener noreferrer"&gt;create a project, and copy the API KEY from the dashboard.&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  What does &lt;code&gt;signInWithWebAuthnOrLink&lt;/code&gt; do?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If the email is not recognized as a user&lt;/strong&gt; , then Cotter will ask the user to verify their email by sending a MagicLink. After the user verified their email, Cotter's SDK will ask the user to enable WebAuthn login by registering the current device.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If the email is a user that has WebAuthn set up&lt;/strong&gt; , then Cotter will try to authenticate the user with WebAuthn. Alternatively, the user can choose to send a magic link to their email to login.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation with vanilla JS
&lt;/h2&gt;

&lt;p&gt;To learn more about WebAuthn, here's a more in-depth explanation about how to implement WebAuthn with purely JavaScript. Check out &lt;a href="https://developer.apple.com/videos/play/wwdc2020/10670/" rel="noopener noreferrer"&gt;Apple's guide from WWDC20&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Registration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Your site requests the server for registering WebAuthn.
&lt;/h4&gt;

&lt;p&gt;Ask the user to enter some identifier (username, email, etc), then send the request to your server asking to register a new WebAuthn credential.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: The server specifies some options for creating the new keypair.
&lt;/h4&gt;

&lt;p&gt;The server specify a &lt;code&gt;PublicKeyCredentialCreationOptions&lt;/code&gt; object that contains some required and optional fields for creating the new &lt;code&gt;PublicKeyCredential&lt;/code&gt; (our keypair).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optionsFromServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;challenge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;random_string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// need to convert to ArrayBuffer&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// my website info&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My Website&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mywebsite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// user info&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthony@email.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                  
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;displayName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Anthony&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USER_ID_12345678910&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// need to convert to ArrayBuffer&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pubKeyCredParams&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="c1"&gt;// Accepted Algorithm&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authenticatorSelection&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;authenticatorAttachment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;platform&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt; &lt;span class="c1"&gt;// in milliseconds&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;rp&lt;/code&gt; : This is for specifying information about the relying party. The relying party is the website where the user is registering/logging-in into. If the user is registering to &lt;strong&gt;your website&lt;/strong&gt; , then your website is the relying party.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;: The host's domain name, without the scheme or port. For example, if the RP's origin is &lt;code&gt;https://login.example.com:1337&lt;/code&gt;, then the &lt;code&gt;id&lt;/code&gt; is &lt;code&gt;login.example.com&lt;/code&gt; or &lt;code&gt;example.com&lt;/code&gt;, but not &lt;code&gt;m.login.example.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;pubKeyCredParams&lt;/code&gt; : What public key types are acceptable to the server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;alg&lt;/code&gt; : A number that describes what algorithm the server accepts, and is described in the &lt;a href="https://www.iana.org/assignments/cose/cose.xhtml#algorithms" rel="noopener noreferrer"&gt;COSE registry&lt;/a&gt; under &lt;strong&gt;COSE Algorithms.&lt;/strong&gt; For example, -7 is for ES256 algorithm.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;authenticatorSelection&lt;/code&gt; : (Optional) Restrict authenticator to be either &lt;code&gt;platform&lt;/code&gt; or &lt;code&gt;cross-platform&lt;/code&gt;. Use &lt;code&gt;platform&lt;/code&gt; to allow authenticators like Windows Hello or TouchID. Use &lt;code&gt;cross-platform&lt;/code&gt; to allow authenticators like Yubikey.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: In the front-end, use the options to create a new keypair.
&lt;/h4&gt;

&lt;p&gt;Using our &lt;code&gt;creationOptions&lt;/code&gt; , we can now tell the browser to generate a new keypair.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// make sure you've converted the strings to ArrayBuffer&lt;/span&gt;
&lt;span class="c1"&gt;// as mentioned above&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;credential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;optionsFromServer&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;credential&lt;/code&gt; that is returned will look like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;PublicKeyCredential&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ABCDESKa23taowh09w0eJG...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;rawId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthenticatorAttestationResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;clientDataJSON&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;121&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;attestationObject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;306&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Send the &lt;code&gt;credential&lt;/code&gt; to your server
&lt;/h4&gt;

&lt;p&gt;First, you might need to convert the &lt;code&gt;ArrayBuffer&lt;/code&gt;s to either base64 encoded strings or just to string. You'll need to decode this in your server.&lt;/p&gt;

&lt;p&gt;Follow &lt;a href="https://w3c.github.io/webauthn/#sctn-registering-a-new-credential" rel="noopener noreferrer"&gt;the specifications to validate the &lt;code&gt;credential&lt;/code&gt; in your server&lt;/a&gt;. You should then store the Credential information to allow the user to login with this WebAuthn Credential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Login
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Send a request to your server to login
&lt;/h4&gt;

&lt;p&gt;This allows the server to send a challenge that your front-end needs to sign.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: The server sends a challenge and a list of WebAuthn credentials that the user can log in from.
&lt;/h4&gt;

&lt;p&gt;The server specify a &lt;code&gt;PublicKeyCredentialRequestOptions&lt;/code&gt; object that contains the challenge to sign and a list of WebAuthn credentials that the user has registered previously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;optionsFromServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;challenge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;somerandomstring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Need to convert to ArrayBuffer&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rpId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mywebsite.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;allowCredentials&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AdPc7AjUmsefw37...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Need to convert to ArrayBuffer&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: The front-end signs the challenge
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// make sure you've converted the strings to ArrayBuffer&lt;/span&gt;
&lt;span class="c1"&gt;// as mentioned above&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assertion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;publicKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;optionsFromServer&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;assertion&lt;/code&gt; that is returned looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;PublicKeyCredential&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ABCDESKa23taowh09w0eJG...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// The WebAuthn Credential ID&lt;/span&gt;
    &lt;span class="nx"&gt;rawId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AuthenticatorAssertionResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;authenticatorData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;191&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;clientDataJSON&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;118&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// The signature that we need to verify&lt;/span&gt;
        &lt;span class="nx"&gt;userHandle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ArrayBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: Send the &lt;code&gt;assertion&lt;/code&gt; to your server and verify it
&lt;/h4&gt;

&lt;p&gt;You might need to convert the ArrayBuffers to a string before sending it to the server. Follow &lt;a href="https://w3c.github.io/webauthn/#sctn-verifying-assertion" rel="noopener noreferrer"&gt;the specifications on verifying the assertion&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When the assertion is verified, this means that &lt;strong&gt;the user has successfully logged in&lt;/strong&gt;. This would be the place to generate your session tokens or set your cookies and return to the front-end.&lt;/p&gt;

&lt;h3&gt;
  
  
  A few things to think about:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;If the user logs in with their laptop's TouchID, how do you allow them to log in from someone else's laptop?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It might be a bad user experience if they can only log in from their own laptop. A possible way is to use WebAuthn as an &lt;strong&gt;alternative&lt;/strong&gt; , and always have a fallback login method (for example, using magic links or OTP).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding more than one WebAuthn credential for one account.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You might want to have a "Settings" page that allows your user to allow WebAuthn login from other devices. For example, they want to login with WebAuthn both from their laptop and their iPad.&lt;/p&gt;

&lt;p&gt;The browser doesn't know which credentials you have saved in your server for a user. If your user already registered their laptop's WebAuthn credential, you need to tell the browser so that it doesn't create a new credential. Use the &lt;code&gt;excludeCredentials&lt;/code&gt; in the &lt;code&gt;PublicKeyCredentialCreationOptions&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support for WebAuthn
&lt;/h3&gt;

&lt;p&gt;Not all browsers support WebAuthn yet, but it's growing. Check out &lt;a href="https://fidoalliance.org/fido2/fido2-web-authentication-webauthn/" rel="noopener noreferrer"&gt;FIDO's website for a list of Browsers and Platforms that supports WebAuthn&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  That's It!
&lt;/h3&gt;

&lt;p&gt;This should cover the basics about registering and logging-in with WebAuthn, and help you implement it on your site. This post is written by the team at &lt;a href="https://www.cotter.app/" rel="noopener noreferrer"&gt;Cotter&lt;/a&gt; – we are building lightweight, fast, and passwordless login solution for websites and mobile apps.&lt;/p&gt;

&lt;p&gt;If you want to implement WebAuthn, our documentation might help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.cotter.app/quickstart-guides/react-webauthn" rel="noopener noreferrer"&gt;React Quickstart – Login with WebAuthn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cotter.app/sdk-reference/web/sign-in-with-webauthn" rel="noopener noreferrer"&gt;WebAuthn SDK Reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;We referred to these incredibly helpful articles to write this post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webauthn.guide/" rel="noopener noreferrer"&gt;WebAuthn Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://w3c.github.io/webauthn/" rel="noopener noreferrer"&gt;WebAuthn Specs from W3C&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Questions &amp;amp; Feedback
&lt;/h3&gt;

&lt;p&gt;If you need help or have any feedback, ping us on &lt;a href="https://join.slack.com/t/askcotter/shared_invite/zt-dxzf311g-5Mp3~odZNB2DwYaxIJ1dJA" rel="noopener noreferrer"&gt;Cotter's Slack Channel&lt;/a&gt;! We're here to help.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ready to use Cotter?
&lt;/h3&gt;

&lt;p&gt;If you enjoyed this post and want to integrate Cotter into your website or app, you can &lt;a href="https://dev.cotter.app/" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; and &lt;a href="https://docs.cotter.app/" rel="noopener noreferrer"&gt;check out our documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>authentication</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>LocalStorage vs Cookies: All You Need To Know About Storing JWT Tokens Securely in The Front-End</title>
      <dc:creator>Michelle Marcelline</dc:creator>
      <pubDate>Tue, 21 Jul 2020 18:20:34 +0000</pubDate>
      <link>https://forem.com/cotter/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end-15id</link>
      <guid>https://forem.com/cotter/localstorage-vs-cookies-all-you-need-to-know-about-storing-jwt-tokens-securely-in-the-front-end-15id</guid>
      <description>&lt;h4&gt;
  
  
  &lt;em&gt;JWT Tokens are awesome, but how do you store them securely in your front-end? We'll go over the pros and cons of localStorage and Cookies.&lt;/em&gt;
&lt;/h4&gt;




&lt;p&gt;We went over &lt;a href="https://blog.cotter.app/what-on-earth-is-oauth-super-simple-intro-to-oauth-20-access-tokens-and-how-to-implement-it-in-your-site/" rel="noopener noreferrer"&gt;how OAuth 2.0 works&lt;/a&gt; in the last post and we covered how to generate access tokens and refresh tokens. The next question is: &lt;strong&gt;how do you store them securely in your front-end?&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  A Recap about Access Token &amp;amp; Refresh Token
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Access tokens&lt;/strong&gt; are usually short-lived JWT Tokens, signed by your server, and are included in every HTTP request to your server to authorize the request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Refresh tokens&lt;/strong&gt; are usually long-lived opaque strings stored in your database and are used to get a new access token when it expires.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where should I store my tokens in the front-end?
&lt;/h2&gt;

&lt;p&gt;There are 2 common ways to store your tokens: in &lt;code&gt;localStorage&lt;/code&gt; or cookies. There are a lot of debate on which one is better and most people lean toward cookies for being more secure.&lt;/p&gt;

&lt;p&gt;Let's go over the comparison between &lt;code&gt;localStorage&lt;/code&gt;. This article is mainly based on &lt;a href="https://dev.to/rdegges/please-stop-using-local-storage-1i04"&gt;Please Stop Using Local Storage&lt;/a&gt; and the comments to this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Storage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros: It's convenient.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's pure JavaScript and it's convenient. If you don't have a back-end and you're relying on a third-party API, you can't always ask them to set a specific cookie for your site.&lt;/li&gt;
&lt;li&gt;Works with APIs that require you to put your access token in the header like this: &lt;code&gt;Authorization Bearer ${access_token}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons: It's vulnerable to XSS attacks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An XSS attack happens when an attacker can run JavaScript on your website. This means that the attacker can just take the access token that you stored in your &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An XSS attack can happen from a third-party JavaScript code included in your website, like React, Vue, jQuery, Google Analytics, etc. It's almost impossible not to include any third-party libraries in your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cookies
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros: The cookie is not accessible via JavaScript; hence, it is not as vulnerable to XSS attacks as &lt;code&gt;localStorage&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you're using &lt;code&gt;httpOnly&lt;/code&gt; and &lt;code&gt;secure&lt;/code&gt; cookies, that means your cookies cannot be accessed using JavaScript. This means, even if an attacker can run JS on your site, they can't read your access token from the cookie.&lt;/li&gt;
&lt;li&gt;It's automatically sent in every HTTP request to your server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons: Depending on the use case, you might not be able to store your tokens in the cookies.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cookies have a size limit of 4KB. Therefore, if you're using a big JWT Token, storing in the cookie is not an option.&lt;/li&gt;
&lt;li&gt;There are scenarios where you can't share cookies with your API server or the API requires you to put the access token in the Authorization header. In this case, you won't be able to use cookies to store your tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About XSS Attack
&lt;/h2&gt;

&lt;p&gt;Local storage is vulnerable because it's easily accessible using JavaScript and an attacker can retrieve your access token and use it later. However, while &lt;code&gt;httpOnly&lt;/code&gt; cookies are not accessible using JavaScript, &lt;strong&gt;this doesn't mean that by using cookies, you are safe from XSS attacks involving your access token.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an attacker can run JavaScript in your application, then they can just send an HTTP request to your server and that will automatically include your cookies. &lt;strong&gt;It's just less convenient for the attacker because they can't read the content of the token&lt;/strong&gt; although they rarely have to. It might also be more advantageous for the attacker to attack using victim's browser (by just sending that HTTP Request) rather than using the attacker's machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cookies and CSRF Attack
&lt;/h2&gt;

&lt;p&gt;CSRF Attack is an attack that forces a user to do an unintended request. For example, if a website is accepting an email change request via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/email/change&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;site.com&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/x-www-form-urlencoded&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50&lt;/span&gt;
&lt;span class="na"&gt;Cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;session=abcdefghijklmnopqrstu&lt;/span&gt;

email=myemail.example.com 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then an attacker can easily make a &lt;code&gt;form&lt;/code&gt; in a malicious website that sends a POST request to &lt;code&gt;https://site.com/email/change&lt;/code&gt; with a hidden email field and the &lt;code&gt;session&lt;/code&gt; cookie will automatically be included.&lt;/p&gt;

&lt;p&gt;However, this can be mitigated easily using &lt;code&gt;sameSite&lt;/code&gt; flag in your cookie and by including an &lt;a href="https://owasp.org/www-community/Anti_CRSF_Tokens_ASP-NET" rel="noopener noreferrer"&gt;anti-CSRF token&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although cookies still have some vulnerabilities, it's preferable compared to &lt;code&gt;localStorage&lt;/code&gt; whenever possible. Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both &lt;code&gt;localStorage&lt;/code&gt; and cookies are vulnerable to XSS attacks but it's harder for the attacker to do the attack when you're using httpOnly cookies.&lt;/li&gt;
&lt;li&gt;Cookies are vulnerable to CSRF attacks but it can be mitigated using &lt;code&gt;sameSite&lt;/code&gt; flag and &lt;a href="https://owasp.org/www-community/Anti_CRSF_Tokens_ASP-NET" rel="noopener noreferrer"&gt;anti-CSRF tokens&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can still make it work even if you need to use the &lt;code&gt;Authorization: Bearer&lt;/code&gt; header or if your JWT is larger than 4KB.
This is also consistent with the recommendation from the OWASP community:&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not store session identifiers in local storage as the data are always accessible by JavaScript. Cookies can mitigate this risk using the &lt;code&gt;httpOnly&lt;/code&gt; flag.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP: HTML5 Security Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  So, how do I use cookies to persists my OAuth 2.0 tokens?
&lt;/h2&gt;

&lt;p&gt;As a recap, here are the different ways you can store your tokens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option 1:&lt;/strong&gt; Store your access token in &lt;code&gt;localStorage&lt;/code&gt; : prone to XSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Option 2:&lt;/strong&gt; Store your access token in &lt;code&gt;httpOnly&lt;/code&gt; cookie: prone to CSRF but can be mitigated, a bit better in terms of exposure to XSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Option 3:&lt;/strong&gt; Store the refresh token in &lt;code&gt;httpOnly&lt;/code&gt; cookie: safe from CSRF, a bit better in terms of exposure to XSS.
We'll go over how &lt;strong&gt;Option 3&lt;/strong&gt; works as it is the best out of the 3 options.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Store your access token in memory and store your refresh token in the cookie
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Why is this safe from CSRF?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Although a form submit to &lt;code&gt;/refresh_token&lt;/code&gt; will work and a new access token will be returned, the attacker can't read the response if they're using an HTML form. To prevent the attacker from successfully making a &lt;code&gt;fetch&lt;/code&gt; or &lt;code&gt;AJAX&lt;/code&gt; request and read the response, this requires the Authorization Server's CORS policy to be set up correctly to prevent requests from unauthorized websites.&lt;/p&gt;

&lt;h4&gt;
  
  
  So how does this set up work?
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Return Access Token and Refresh Token when the user is authenticated.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After the user is authenticated, the Authorization Server will return an &lt;code&gt;access_token&lt;/code&gt; and a &lt;code&gt;refresh_token&lt;/code&gt;. The &lt;code&gt;access_token&lt;/code&gt; will be included in the Response body and the &lt;code&gt;refresh_token&lt;/code&gt; will be included in the cookie.&lt;/p&gt;

&lt;p&gt;Refresh Token cookie setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the &lt;code&gt;httpOnly&lt;/code&gt; flag to prevent JavaScript from reading it.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;secure=true&lt;/code&gt; flag so it can only be sent over HTTPS.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;SameSite=strict&lt;/code&gt; flag whenever possible to prevent CSRF. This can only be used if the Authorization Server has the same site as your front-end. If this is not the case, your Authorization Server must set CORS headers in the back-end or use other methods to ensure that the refresh token request can only be done by authorized websites.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Store the access token in memory&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Storing the token in-memory means that you put this access token in a variable in your front-end site. Yes, this means that the access token will be gone if the user switches tabs or refresh the site. That's why we have the refresh token.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Renew access token using the refresh token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When the access token is gone or has expired, hit the &lt;code&gt;/refresh_token&lt;/code&gt; endpoint and the refresh token that was stored in the cookie in step 1 will be included in the request. You'll get a new access token and can then use that for your API Requests.&lt;/p&gt;

&lt;p&gt;This means your JWT Token can be larger than 4KB and you can also put it in the Authorization header.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's It!
&lt;/h2&gt;

&lt;p&gt;This should cover the basics and help you secure your site. This post is written by the team at &lt;a href="https://www.cotter.app/" rel="noopener noreferrer"&gt;Cotter&lt;/a&gt; – we are building lightweight, fast, and passwordless login solution for websites and mobile apps.&lt;/p&gt;

&lt;p&gt;If you're building a login flow for your website or mobile app, these articles might help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.cotter.app/what-on-earth-is-oauth-super-simple-intro-to-oauth-20-access-tokens-and-how-to-implement-it-in-your-site/" rel="noopener noreferrer"&gt;What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.cotter.app/passwordless-login-with-email-and-json-web-token-jwt-authentication-with-nextjs/" rel="noopener noreferrer"&gt;Passwordless Login with Email and JSON Web Token (JWT) Authentication using Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.cotter.app/integrate-cotter-magic-link-to-webflow-in-less-than-15-minutes/" rel="noopener noreferrer"&gt;Here's How to Integrate Cotter's Magic Link to Your Webflow Site in Less Than 15 minutes!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;We referred to several articles when writing this blog, especially from these articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/rdegges/please-stop-using-local-storage-1i04"&gt;Please Stop Using Local Storage&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hasura.io/blog/best-practices-of-using-jwt-with-graphql/#jwt_persist" rel="noopener noreferrer"&gt;The Ultimate Guide to handling JWTs on front-end clients (GraphQL)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://supertokens.io/blog/cookies-vs-localstorage-for-sessions-everything-you-need-to-know" rel="noopener noreferrer"&gt;Cookies vs Localstorage for sessions – everything you need to know&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Questions &amp;amp; Feedback
&lt;/h3&gt;

&lt;p&gt;If you need help or have any feedback, feel free to comment here or ping us on &lt;a href="https://join.slack.com/t/askcotter/shared_invite/zt-dxzf311g-5Mp3~odZNB2DwYaxIJ1dJA" rel="noopener noreferrer"&gt;Cotter's Slack Channel&lt;/a&gt;! We're here to help.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ready to use Cotter?
&lt;/h3&gt;

&lt;p&gt;If you enjoyed this post and want to integrate Cotter into your website or app, you can &lt;a href="https://dev.cotter.app/" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; and &lt;a href="https://docs.cotter.app/" rel="noopener noreferrer"&gt;check out our documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What on Earth Is OAuth? ASuper Simple Intro to OAuth 2.0, Access Tokens, and How to Implement It in Your Site</title>
      <dc:creator>Michelle Marcelline</dc:creator>
      <pubDate>Tue, 14 Jul 2020 17:00:00 +0000</pubDate>
      <link>https://forem.com/cotter/what-on-earth-is-oauth-a-super-simple-intro-to-oauth-2-0-access-tokens-and-how-to-implement-it-in-your-site-48jo</link>
      <guid>https://forem.com/cotter/what-on-earth-is-oauth-a-super-simple-intro-to-oauth-2-0-access-tokens-and-how-to-implement-it-in-your-site-48jo</guid>
      <description>&lt;p&gt;&lt;em&gt;Get a quick intro on what OAuth 2.0 is and how signing in with OAuth 2.0 works – explained in simple terms using Google Sign In as an example.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FCover-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2FCover-1.png" alt="What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're excited to tell you that Cotter now generates access tokens and refresh tokens on authentication. Let's first go over the concepts of OAuth 2.0 and the tokens before we jump in on how to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overview&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is OAuth 2.0&lt;/li&gt;
&lt;li&gt;OAuth 2.0 in Action&lt;/li&gt;
&lt;li&gt;
OAuth Tokens: Short-lived access tokens and long-lived refresh tokens&lt;/li&gt;
&lt;li&gt;How to Implement OAuth 2.0 for your site&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  What is OAuth 2.0?
&lt;/h1&gt;

&lt;p&gt;OAuth 2.0 is an authorization framework that defines how a third-party application can obtain access to a service securely without requiring security details (username, password, etc.) from the user. A common example of OAuth 2.0 is when you use "Sign in with Google" to log in to other websites.&lt;/p&gt;

&lt;h1&gt;
  
  
  OAuth 2.0 in Action
&lt;/h1&gt;

&lt;p&gt;In general, the OAuth 2.0 flow looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-5.png" alt="What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site" width="800" height="400"&gt;&lt;/a&gt;OAuth 2.0 Flow with Google Sign In&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's use "Sign in with Google" as an example.
&lt;/h3&gt;

&lt;p&gt;Albert is a Google Calendar user and he's trying to use Calendly.com to help manage his calendar. &lt;strong&gt;We'll go over the terms in the next example.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(1) Calendly.com wants to access Albert's Google Calendar. Calendly.com redirects Albert to sign in to his Google account where he grants Calendar permission for Calendly.com. (2) Google returns an Authorization Grant and redirects Albert to Calendly.com.
(3) Calendly.com gives the Authorization Grant to Google and (4) receives an Access Token.
(5) Calendly.com can now use this Access Token to (6) access Albert's Google Calendar, but not his Google Drive or other resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, Calendly.com is the client, Albert is the Resource Owner, Google Account is the Authorization Server, and Google Calendar is the Resource Server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's try to understand the terms in a simpler example.
&lt;/h3&gt;

&lt;p&gt;Let's use an example of Alberta who stays in a hotel and wants to allow her babysitter, Candy, to access her room.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Alberta agrees that Candy shall access her room and asks Candy to get her own room key from the receptionist. Alberta gives Candy &lt;strong&gt;a copy of her ID and a note saying "access during daytime only"&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Candy goes to the receptionist with a copy of Alberta's ID and the note. &lt;strong&gt;The receptionist verifies the ID and gives Candy a special room key&lt;/strong&gt; that can only be used during daytime.
Candy goes back to the room and uses her key to access the room.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-10.png" alt="What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Candy is the Client (just like Calendly.com) who wants to access Alberta's data. Alberta here is granting limited access to the Client. &lt;strong&gt;The Authorization Grant is Alberta's ID copy and her note.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The receptionist is the Authorization Server, they can generate a room key for Candy to access the room. &lt;strong&gt;This room key is the equivalent of an Access Token, it can be used to get resources.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The room lock is the Resource Server, it holds the resource that Candy wants: the room.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;There are several different flows that OAuth 2.0 offers, this example is following the Authorization Code flow. We'll talk about the different flows in a different post :)&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  OAuth Tokens
&lt;/h1&gt;

&lt;p&gt;As mentioned above, at the end of the flow, the client receives an Access Token. Generally, these Access Tokens are &lt;strong&gt;short-lived&lt;/strong&gt;; so, what happens when it expires?&lt;/p&gt;

&lt;h2&gt;
  
  
  Short-lived access tokens and long-lived refresh tokens
&lt;/h2&gt;

&lt;p&gt;At step 4, the Authorization Server can generate 2 tokens, an &lt;strong&gt;access token&lt;/strong&gt; and a &lt;strong&gt;refresh token&lt;/strong&gt;. The access token is short-lived, it should only last from several hours to a couple of weeks.&lt;/p&gt;

&lt;p&gt;When the access token expires, &lt;strong&gt;the application can use the refresh token to obtain a new access token&lt;/strong&gt;. This prevents having to ask the user to re-authenticate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access Token
&lt;/h2&gt;

&lt;p&gt;Alright, now that we understand how things work, let's start thinking about how to generate access tokens. With a short-lived access token, we can &lt;strong&gt;use a JWT Token to make a self-encoded access token&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-6.png" alt="What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site" width="800" height="400"&gt;&lt;/a&gt;How a JWT Token Looks Like&lt;/p&gt;

&lt;p&gt;JSON Web Tokens (JWT) is a signed JSON object. This means you can trust the data contained in the JSON object by verifying the signature. For authorizing a user, you can include the user's ID and email in the JWT.&lt;/p&gt;

&lt;p&gt;When you give the JWT Access Token to the Resource Server (your backend API server), &lt;strong&gt;your server can validate the JWT Token without needing to access the database to check if it's valid.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All your server needs to do is to validate that the JWT Token is valid using a library, see the user ID of the user making the request from the token, and trust that this user ID is already authenticated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refresh Token
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-9.png" alt="What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site" width="800" height="400"&gt;&lt;/a&gt;Renewing Access Token using a Refresh Token&lt;/p&gt;

&lt;p&gt;A refresh token is a special token that is used to obtain a new Access Token. Since this is long-lived, refresh tokens are generally opaque strings stored in the database. Storing refresh tokens in the database allows you to revoke them by deleting it from the database.&lt;/p&gt;

&lt;p&gt;Because there is no way to expire an Access Token, we should make the access token short-lived. Revoking the refresh token prevents malicious parties from refreshing an expired Access Token. This means that if your Access Token expires in 1 hour, then an attacker who obtained your Access Token can only access your API for 1 hour before it expires.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Implement OAuth 2.0 for your site
&lt;/h1&gt;

&lt;p&gt;This sounds like a lot, but you can implement OAuth 2.0 and authorizes API requests using access tokens by using Cotter &lt;strong&gt;in just a few minutes&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your website as the Client, Cotter as the Authorization Server
&lt;/h3&gt;

&lt;p&gt;With the OAuth flow above, here's how it looks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your website is the Client&lt;/li&gt;
&lt;li&gt;Your user is the Resource Owner&lt;/li&gt;
&lt;li&gt;Cotter is the Authorization Server&lt;/li&gt;
&lt;li&gt;Your backend server is the Resource Server&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Logging-in and Generating Access Tokens
&lt;/h2&gt;

&lt;p&gt;We have several 5-minutes quickstarts for authenticating users and generating access tokens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web:&lt;/strong&gt; &lt;a href="https://docs.cotter.app/quickstart-guides/html-magic-link-with-email-and-phone" rel="noopener noreferrer"&gt;HTML&lt;/a&gt; &lt;strong&gt;,&lt;/strong&gt; &lt;a href="https://docs.cotter.app/quickstart-guides/react-magic-link-with-email-and-phone" rel="noopener noreferrer"&gt;React&lt;/a&gt;, &lt;a href="https://dev.to/cotter/angular-send-email-sms-and-whatsapp-verification-code-to-new-users-worldwide-1n1i-temp-slug-1500123"&gt;Angular&lt;/a&gt; (also check out our &lt;a href="https://dev.to/cotter/stop-spending-days-to-code-your-login-page-add-cotter-s-magic-link-to-your-gatsby-app-under-5-minutes-mgl"&gt;Gatsby&lt;/a&gt; and &lt;a href="https://dev.to/cotter/passwordless-login-with-email-and-json-web-token-jwt-authentication-using-next-js-4b8f-temp-slug-7505363"&gt;Next.js&lt;/a&gt; tutorials).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile:&lt;/strong&gt; &lt;a href="https://docs.cotter.app/sdk-reference/react-native/react-native-sdk-verify-email-phone" rel="noopener noreferrer"&gt;React Native&lt;/a&gt;, &lt;a href="https://docs.cotter.app/sdk-reference/flutter/sign-in-with-email-phone-number" rel="noopener noreferrer"&gt;Flutter&lt;/a&gt;, &lt;a href="https://docs.cotter.app/sdk-reference/ios/ios-sdk-verify-email-phone" rel="noopener noreferrer"&gt;iOS&lt;/a&gt;, &lt;a href="https://docs.cotter.app/sdk-reference/android/android-sdk-1" rel="noopener noreferrer"&gt;Android&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.cotter.app%2Fcontent%2Fimages%2F2020%2F07%2Fimage-7.png" alt="What On Earth Is OAuth? A Super Simple Intro to OAuth 2.0, Access Tokens, and How to Implement it in your Site" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For this guide, we'll use React as an example.&lt;/strong&gt; We'll build a login form with email magic link and get an access token at the end of the flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import Cotter:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add cotter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialize and show an email login form:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Cotter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cotter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1️⃣ Import Cotter&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 2️⃣ Initialize and show the form&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cotter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cotter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;API_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 👈 Specify your API KEY ID here&lt;/span&gt;
    &lt;span class="nx"&gt;cotter&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signInWithLink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// use Magic link&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showEmailForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// show email login form&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;// 3️⃣ Put a &amp;lt;div&amp;gt; with id "cotter-form-container"&lt;/span&gt;
    &lt;span class="c1"&gt;// that will contain the form&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cotter-form-container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
App.js





&lt;p&gt;You can get your &lt;code&gt;API_KEY_ID&lt;/code&gt; from &lt;a href="https://dev.cotter.app" rel="noopener noreferrer"&gt;the dashboard&lt;/a&gt; by creating a free account.&lt;/p&gt;

&lt;h3&gt;
  
  
  That's it. Check your console logs for an access token.
&lt;/h3&gt;

&lt;p&gt;The function above covers steps 1-4 in the OAuth 2.0 flow. The response from &lt;code&gt;showEmailForm()&lt;/code&gt; returns an access token. As described above, you should then use this access token to access a resource in your backend server.&lt;/p&gt;

&lt;p&gt;For example, you can include this access token to your endpoint &lt;code&gt;/api/private-resource&lt;/code&gt; and you'll &lt;a href="https://docs.cotter.app/getting-access-token/verifying-jwt-tokens" rel="noopener noreferrer"&gt;check if the access token is valid&lt;/a&gt; before continuing with the request.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's Next?
&lt;/h1&gt;

&lt;p&gt;Now that you know how to get access tokens, here's a few more things to wrap up your login flow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.cotter.app/getting-access-token/handling-authentication-with-cotter" rel="noopener noreferrer"&gt;OAuth Tokens from Cotter&lt;/a&gt;: What tokens do you get, and how do they look like.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/cotter/passwordless-login-with-email-and-json-web-token-jwt-authentication-using-next-js-4b8f-temp-slug-7505363"&gt;How to verify the access token and allow requests to private endpoints&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;How to store it securely in the front end. We'll cover this next week, stay tuned!&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Questions &amp;amp; Feedback
&lt;/h3&gt;

&lt;p&gt;If you need help or have any feedback, ping us on &lt;a href="https://join.slack.com/t/askcotter/shared_invite/zt-dxzf311g-5Mp3~odZNB2DwYaxIJ1dJA" rel="noopener noreferrer"&gt;Cotter's Slack Channel&lt;/a&gt;! We're here to help.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ready to use Cotter?
&lt;/h3&gt;

&lt;p&gt;If you enjoyed this tutorial and want to integrate Cotter into your website or app, you can &lt;a href="https://dev.cotter.app/" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; and &lt;a href="https://docs.cotter.app/" rel="noopener noreferrer"&gt;check out our documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>oauth</category>
    </item>
  </channel>
</rss>
