<?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: Aaron Parecki</title>
    <description>The latest articles on Forem by Aaron Parecki (@aaronpk).</description>
    <link>https://forem.com/aaronpk</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%2F293%2F79c9b743-99c8-4851-ad24-618b31308021.jpg</url>
      <title>Forem: Aaron Parecki</title>
      <link>https://forem.com/aaronpk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aaronpk"/>
    <language>en</language>
    <item>
      <title>How to export your complete Foursquare checkin history</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Wed, 03 Nov 2021 15:22:31 +0000</pubDate>
      <link>https://forem.com/aaronpk/how-to-export-your-complete-foursquare-checkin-history-pkj</link>
      <guid>https://forem.com/aaronpk/how-to-export-your-complete-foursquare-checkin-history-pkj</guid>
      <description>&lt;p&gt;Today I finished up a tool that you can use to export your complete history from Foursquare and publish the checkins to your website!&lt;/p&gt;

&lt;p&gt;In 2017, I created &lt;a href="https://ownyourswarm.p3k.io"&gt;OwnYourSwarm&lt;/a&gt; to export my future Swarm checkins to my website in real-time. It's been working great, and it's meant that I have had a complete archive of all my checkins on my website ever since then, so I don't have to worry if Foursquare disappears one day. However, I never got around to creating a way to export my past checkins, so I was always missing my checkin history from 2009-2016.&lt;/p&gt;

&lt;p&gt;I had been considering building this as a feature of OwnYourSwarm, but realized that it would end up taking a lot of additional effort to make it work well as a web service, in addition to dealing with possible rate limit issues with the Foursquare API. So instead, this is published as a downloadable script you can run on your own computer. This also means you have a bit more flexibility in how you can use it, as well as being able to customize it more if you choose.&lt;/p&gt;

&lt;p&gt;You can download the code from GitHub here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aaronpk/Swarm-Checkins-Import"&gt;https://github.com/aaronpk/Swarm-Checkins-Import&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The readme has installation and usage instructions, so I'll refrain from repeating all that in this post. Make sure to check out the step by step tutorial in the readme if you want to use this with your own account.&lt;/p&gt;

&lt;p&gt;The process is broken up into a couple steps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, it downloads your entire Foursquare checkin history to JSON files on your computer&lt;/li&gt;
&lt;li&gt;Second, it downloads all the photos from your checkins&lt;/li&gt;
&lt;li&gt;Third, it publishes each checkin to your website via &lt;a href="https://micropub.net"&gt;Micropub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your website doesn't support checkins via Micropub, or if you don't want your checkins on your website at all, you can just skip that step entirely, and instead you'll have a complete export of your data locally.&lt;/p&gt;

&lt;p&gt;The JSON files contain the raw API response from Foursquare, so you can do what you want with that as well, such as turning it into your own HTML archive using your own custom tools if you want.&lt;/p&gt;

&lt;p&gt;The one issue that I don't have a good solution for is handling renamed venues. Unfortunately the API returns the current name for old checkins, so if a venue is renamed, your old checkins will not reflect the name at the time of the checkin. This is particularly strange for businesses that have gone through an acquisition or rebranding, since for example all my old checkins in Green Dragon are now labeled as Rogue Eastside Brewery. As far as I can tell there isn't a good way to handle this, so I may have to go back and manually edit the posts on my website for the venues I know have been renamed.&lt;/p&gt;

&lt;p&gt;I hope this is useful to people! I will be sleeping a little easier now knowing that my old checkin history is safely archived on my website now!&lt;/p&gt;

</description>
      <category>export</category>
      <category>ownyourdata</category>
      <category>foursquare</category>
      <category>swarm</category>
    </item>
    <item>
      <title>Is the OAuth 2.0 Implicit Flow Dead?</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Wed, 01 May 2019 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/is-the-oauth-2-0-implicit-flow-dead-4el8</link>
      <guid>https://forem.com/oktadev/is-the-oauth-2-0-implicit-flow-dead-4el8</guid>
      <description>&lt;p&gt;You may have heard some buzz recently about the OAuth 2.0 Implicit flow. The OAuth Working Group has published some new guidance around the Implicit flow and JavaScript-based apps, specifically that the Implicit flow should no longer be used. In this post, we’ll look at what’s changing with the Implicit flow and why.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CHzERullHe8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Practice Around Implicit in OAuth 2.0 is Changing
&lt;/h2&gt;

&lt;p&gt;The Implicit flow in OAuth 2.0 was created nearly ten years ago when browsers worked very differently than they do today. The primary reason the Implicit flow was created was because of an old limitation in browsers. It used to be the case that JavaScript could only make requests to the same server that the page was loaded from. However, the standard OAuth Authorization Code flow requires that a POST request is made to the OAuth server’s token endpoint, which is often on a different domain than the app. That meant there was previously no way to use this flow from JavaScript. The Implicit flow worked around this limitation by avoiding that POST request, and instead of returning the access token immediately in the redirect.&lt;/p&gt;

&lt;p&gt;Today, Cross-Origin Resource Sharing (CORS) is universally adopted by browsers, removing the need for this compromise. CORS provides a way for JavaScript to make requests to servers on a different domain as long as the destination allows it. This opens up the possibility of using the Authorization Code flow in JavaScript.&lt;/p&gt;

&lt;p&gt;It’s worth noting that the Implicit flow has always been seen as a compromise compared to the Authorization Code flow. For example, the spec provides no mechanism to return a refresh token in the Implicit flow, as it was seen as too insecure to allow that. The spec also recommends short lifetimes and limited scope for access tokens issued via the Implicit flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OAuth Authorization Code Flow is Better
&lt;/h2&gt;

&lt;p&gt;Now that it is possible to use the Authorization Code flow from a browser, we still have one more issue to deal with regarding JavaScript apps. Traditionally the Authorization Code flow uses a client secret when exchanging the authorization code for an access token, but there is no way to include a client secret in a JavaScript app and have it remain a secret. If you were to include a secret in the source code, anyone using the app could just “view source” in their browser and see it. So we need a solution.&lt;/p&gt;

&lt;p&gt;Thankfully, this problem has already been solved, since the same issue applies to mobile apps as well. As we’ve &lt;a href="https://www.youtube.com/watch?v=H6MxsFMAoP8" rel="noopener noreferrer"&gt;seen in the past&lt;/a&gt;, native apps also can’t safely use a client secret. The OAuth working group solved this problem several years ago with the PKCE extension to the Authorization Code flow.&lt;/p&gt;

&lt;p&gt;The Authorization Code flow with PKCE adds an additional step, which allows us to protect the authorization code so that even if it is stolen during the redirect, it will be useless by itself. You can read more about how PKCE works in our blog post, &lt;a href="https://developer.okta.com/blog/2018/12/13/oauth-2-for-native-and-mobile-apps" rel="noopener noreferrer"&gt;OAuth 2.0 for Native and Mobile Apps&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The OAuth 2.0 Implicit Flow for Existing Apps
&lt;/h2&gt;

&lt;p&gt;The important thing to remember here is that there was no new vulnerability found in the Implicit flow. If you have an existing app that uses the Implicit flow, it’s not that your app is suddenly now insecure after this new guidance has been published.&lt;/p&gt;

&lt;p&gt;That said, it is – and always has been – extremely challenging to implement the Implicit flow securely. If you have gone to the trouble of thoroughly auditing your source code, knowing exactly which third-party libraries you’re using in your application, have a strong Content Security Policy, and are confident in your ability to build a secure JavaScript application, then your application is probably fine.&lt;/p&gt;

&lt;p&gt;So should you immediately switch all your apps to using PKCE instead of the Implicit flow? Probably not, it depends on your risk tolerance. But at this point, I would definitely not recommend creating &lt;em&gt;new&lt;/em&gt; apps using the Implicit flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the Authorization Code Flow Make Browser-Based Apps Totally Secure?
&lt;/h2&gt;

&lt;p&gt;Unfortunately, there is no such thing as perfect security. Especially in browsers, there are always many ways an application may be attacked. The best we can do is protect against common attacks, and reduce the overall attack surface of an application.&lt;/p&gt;

&lt;p&gt;Specifically, the Authorization Code flow with PKCE does completely protect the application from the attack where an authorization code is stolen in transit back to the application. However, once the JavaScript app has obtained an access token, it will still have to store it somewhere in order to use it, and how it stores the access token will be the same whether the app used the Implicit flow or PKCE to obtain it. You’ll still need to ensure you have a good Content Security Policy and are aware of any third-party libraries you’re using in your application.&lt;/p&gt;

&lt;p&gt;The best way to securely implement OAuth in a JavaScript app is to keep the token management outside of JavaScript entirely. If you’re building a JavaScript app that is served from a dynamic server, such as a &lt;a href="https://developer.okta.com/blog/2018/08/22/basic-crud-angular-7-and-spring-boot-2" rel="noopener noreferrer"&gt;Spring Boot backend with an Angular frontend&lt;/a&gt;, or an &lt;a href="https://developer.okta.com/blog/2018/07/02/build-a-secure-crud-app-with-aspnetcore-and-react" rel="noopener noreferrer"&gt;ASP.NET backend with a React front-end&lt;/a&gt;, then you can keep all of the OAuth exchange and token management inside the backend, never exposing it to the JavaScript front-end, and avoid all the risks inherent in managing tokens in JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Using the Implicit Flow with PKCE in JavaScript Today
&lt;/h2&gt;

&lt;p&gt;So you’re ready to start writing an app using PKCE in JavaScript? Let’s take a look at exactly what that entails.&lt;/p&gt;

&lt;p&gt;For the purposes of this demonstration, let’s assume you want to implement this in pure JavaScript, with no additional libraries required. This will illustrate exactly how PKCE works, which you should then be able to translate into your particular framework of choice.&lt;/p&gt;

&lt;p&gt;First, &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;sign up for a free Okta Developer account&lt;/a&gt;. Once you’ve signed up, select &lt;strong&gt;Applications&lt;/strong&gt; from the menu at the top of the page, and click &lt;strong&gt;Add Application&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2F88ea1755a2442f59c59af60ea419603488e96c05%2F715a3%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fadd-application-9850fc5e93dfd1f9c390d7103cc689f839423fb7b554f9789fddcf670e4b1c91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2F88ea1755a2442f59c59af60ea419603488e96c05%2F715a3%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fadd-application-9850fc5e93dfd1f9c390d7103cc689f839423fb7b554f9789fddcf670e4b1c91.png" alt="Add an application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Single-Page App&lt;/strong&gt; from the options, which will configure this application to enable the CORS headers on the token endpoint, and will not create a client secret.&lt;/p&gt;

&lt;p&gt;Give your application a name, and then there are two settings you’ll need to change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2Fe5a0ed2d4d0d93ea4ae6ebf65c8a45f4f765b68d%2F8e231%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fapplication-details-582b86dba287307c3e17e0faa7bef790faa05a34043fd2e6d7579c48383e7667.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2Fe5a0ed2d4d0d93ea4ae6ebf65c8a45f4f765b68d%2F8e231%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fapplication-details-582b86dba287307c3e17e0faa7bef790faa05a34043fd2e6d7579c48383e7667.png" alt="Application details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change the &lt;strong&gt;Login redirect URI&lt;/strong&gt; to match the base URI since we’ll be building a single-page app in just one HTML file.&lt;/p&gt;

&lt;p&gt;Also, make sure to check the &lt;strong&gt;Authorization Code&lt;/strong&gt; checkbox, and uncheck &lt;strong&gt;Implicit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That will register the application and provide you with a &lt;code&gt;client_id&lt;/code&gt; on the next screen. Make a note of this value since we’ll need it again later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2Ff0bc25d787afba0a9fe49ccf1a857263b83021fd%2Fdb4b0%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fclient-id-c1c9df402378300db458721e5e81535d2fa23a9668718bef7fd159cd38d47f10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2Ff0bc25d787afba0a9fe49ccf1a857263b83021fd%2Fdb4b0%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fclient-id-c1c9df402378300db458721e5e81535d2fa23a9668718bef7fd159cd38d47f10.png" alt="Client ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a new folder, and create an HTML file in it called &lt;code&gt;index.html&lt;/code&gt; with the following contents. Fill in your Client ID in the config block below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;OAuth Authorization Code + PKCE in Vanilla JS&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1, user-scalable=no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// Configure your application and authorization server details&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:8080/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;authorization_endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;token_endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;requested_scopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;openid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to find the authorization endpoint and token endpoint for your OAuth server. Navigate to &lt;strong&gt;API&lt;/strong&gt; in the main menu at the top, then choose &lt;strong&gt;Authorization Servers&lt;/strong&gt;. You will probably have only one server in that list, “default”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2Fa9ed45b40b8c54c98d8c3c40026bab653f0be5f3%2F29c8c%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fdefault-authorization-server-df877dc542a03210f9629bf52558ef9f6ee6ac20fe33886f7860dcf617502aa1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2Fa9ed45b40b8c54c98d8c3c40026bab653f0be5f3%2F29c8c%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fdefault-authorization-server-df877dc542a03210f9629bf52558ef9f6ee6ac20fe33886f7860dcf617502aa1.png" alt="Default authorization server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the Issuer URI from that authorization server. Your authorization endpoint will be that URI with &lt;code&gt;/v1/auth&lt;/code&gt; appended, and the token endpoint will end with &lt;code&gt;/v1/token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, if your Issuer URI is &lt;code&gt;https://{yourOktaDomain}/oauth2/default&lt;/code&gt;, then your authorization endpoint will be &lt;code&gt;https:/{yourOktaDomain}/oauth2/defalut/v1/auth&lt;/code&gt; and your token endpoint will be &lt;code&gt;https://{yourOktaDomain}/oauth2/default/v1/token&lt;/code&gt;. Enter those two values in the JavaScript config object created in the previous step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up the HTML Structure
&lt;/h3&gt;

&lt;p&gt;Next, let’s add some HTML to the page to create a couple of UI elements to help illustrate this flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-center full-height"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"start"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click to Sign In&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"token"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Access Token&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"access_token"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Error&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"error_details"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to make it look good, add the following CSS below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&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="nc"&gt;.full-height&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.flex-center&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.content&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.code&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;"Courier New"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;"Courier"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;monospace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;#ccc&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;word-break&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;break-all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.hidden&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Begin the PKCE Request
&lt;/h3&gt;

&lt;p&gt;With that out of the way, we can get to the good stuff, actually starting the PKCE flow in JavaScript. First, add a new &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag so that we have a place to start writing JavaScript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’re first going to define a few helper functions that will take care of the tricky parts of PKCE: securely generating a random string, and generating the SHA256 hash of that string.&lt;/p&gt;

&lt;p&gt;Add these functions into the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag you just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PKCE HELPER FUNCTIONS&lt;/span&gt;

&lt;span class="c1"&gt;// Generate a secure random string using the browser crypto functions&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateRandomString&lt;/span&gt;&lt;span class="p"&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;array&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;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dec&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&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;// Calculate the SHA256 hash of the input text. &lt;/span&gt;
&lt;span class="c1"&gt;// Returns a promise that resolves to an ArrayBuffer&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plain&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="nx"&gt;encoder&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;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SHA-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Base64-urlencodes the input string&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;base64urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Convert the ArrayBuffer to string using Uint8 array to convert to what btoa accepts.&lt;/span&gt;
    &lt;span class="c1"&gt;// btoa accepts chars only within ascii 0-255 and base64 encodes them.&lt;/span&gt;
    &lt;span class="c1"&gt;// Then convert the base64 encoded to base64url encoded&lt;/span&gt;
    &lt;span class="c1"&gt;// (replace + with -, replace / with _, trim trailing =)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromCharCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\+&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/=+$/&lt;/span&gt;&lt;span class="p"&gt;,&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;// Return the base64-urlencoded sha256 hash for the PKCE challenge&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pkceChallengeFromVerifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;hashed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;base64urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hashed&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;p&gt;Now we’re ready to kick off the flow. The first step of the PKCE flow is to generate a secret, hash it, then redirect the user over to the authorization server with that hash in the URL.&lt;/p&gt;

&lt;p&gt;We’ll add an &lt;code&gt;onclick&lt;/code&gt; listener to the &lt;code&gt;Click to Sign In&lt;/code&gt; link we created in the HTML.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Initiate the PKCE Auth Code flow when the link is clicked&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Create and store a random "state" value&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateRandomString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkce_state&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Create and store a new PKCE code_verifier (the plaintext random secret)&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;code_verifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateRandomString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkce_code_verifier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;code_verifier&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Hash and base64-urlencode the secret to use as the challenge&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;code_challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pkceChallengeFromVerifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code_verifier&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Build the authorization URL&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization_endpoint&lt;/span&gt; 
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;?response_type=code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;client_id=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;state=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;scope=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requested_scopes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;redirect_uri=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;code_challenge=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code_challenge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;code_challenge_method=S256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Redirect to the authorization server&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&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;p&gt;This function does a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a random string to use as the &lt;code&gt;state&lt;/code&gt; value and stores it in &lt;code&gt;LocalStorage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates a random string to use as the PKCE &lt;code&gt;code_verifier&lt;/code&gt; value&lt;/li&gt;
&lt;li&gt;Hashes and base64-urlencodes the code verifier&lt;/li&gt;
&lt;li&gt;Builds the authorization URL with all the required parameters, using the config values you defined at the beginning&lt;/li&gt;
&lt;li&gt;Redirects the browser to the authorization URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, the user is handed off to the authorization server to log in. The authorization server will then redirect the user back to the application, and there will be two parameters in the query string: &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;state&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Get an Access Token using the Authorization Code
&lt;/h3&gt;

&lt;p&gt;This application will need to verify the &lt;code&gt;state&lt;/code&gt; value matches the one it generated at the beginning, then exchange the authorization code for an access token. To accomplish this, we’ll need to add a couple more helper functions.&lt;/p&gt;

&lt;p&gt;Add the following function to the bottom of your JavaScript. This function will parse a query string into a JavaScript object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Parse a query string into an object&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseQueryString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;==&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&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;segments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;=&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;queryString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;queryString&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;queryString&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;p&gt;Also, add the function below, which will give us an easy way to make a POST request and parse the JSON response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Make a POST request and parse the response as JSON&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendPostRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&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;request&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;XMLHttpRequest&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-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="s1"&gt;application/x-www-form-urlencoded; charset=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&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;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&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;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&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="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;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&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="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&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;p&gt;Now you’re ready to exchange the authorization code for an access token. If you’re familiar with the traditional Authorization Code flow, you’ll remember that this step normally requires a client secret. But since we don’t have a client secret for this JavaScript application, instead we’ll send the PKCE code verifier when making this request, which ensures that only the application that requested a code can exchange it for an access token.&lt;/p&gt;

&lt;p&gt;Add the following code to your JavaScript section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Handle the redirect back from the authorization server and&lt;/span&gt;
&lt;span class="c1"&gt;// get an access token from the token endpoint&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseQueryString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Check if the server returned an error string&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error returned from authorization server: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error_details&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error_description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt; &lt;span class="o"&gt;=&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;// If the server returned an authorization code, attempt to exchange it for an access token&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Verify state matches what we set at the beginning&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkce_state&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="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid state&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Exchange the authorization code for an access token&lt;/span&gt;
        &lt;span class="nf"&gt;sendPostRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token_endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;grant_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;authorization_code&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;code_verifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkce_code_verifier&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="c1"&gt;// Initialize your application now that you have an access token.&lt;/span&gt;
            &lt;span class="c1"&gt;// Here we just display it in the browser.&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;access_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hidden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Replace the history entry to remove the auth code from the browser address bar&lt;/span&gt;
            &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replaceState&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// This could be an error response from the OAuth server, or an error because the &lt;/span&gt;
            &lt;span class="c1"&gt;// request failed such as if the OAuth server doesn't allow CORS requests&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error_details&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error_description&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt; &lt;span class="o"&gt;=&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="c1"&gt;// Clean these up since we don't need them anymore&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkce_state&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pkce_code_verifier&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code does a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks if the authorization server returned an error message and displays it to the user if so&lt;/li&gt;
&lt;li&gt;Checks if the authorization server returned an authorization code, and exchanges it for an access token&lt;/li&gt;
&lt;li&gt;Sends a POST request to the token endpoint which includes the &lt;code&gt;code_verifier&lt;/code&gt; parameter that is made in the previous step&lt;/li&gt;
&lt;li&gt;Updates the UI to indicate error messages or show the access token returned&lt;/li&gt;
&lt;li&gt;Removes the authorization code from the address bar using the Session History Management API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, you’re ready to try out the application! You’ll need to either run a local web server or host it on a test domain. In any case, just make sure that the &lt;strong&gt;Base URI&lt;/strong&gt; and &lt;strong&gt;Redirect URI&lt;/strong&gt; in your application settings are set to the URL that you’ll be visiting this application. (Also note that this will not work just opening the page from your filesystem due to cross-domain restrictions that browser have with &lt;code&gt;file://&lt;/code&gt; URIs).&lt;/p&gt;

&lt;p&gt;You can use any webserver to serve the file, but I find that an easy way to launch this app is to use PHP’s built-in web server. You can run the command below to start a web server on port 8080:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; localhost:8080

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now visit &lt;code&gt;http://localhost:8080/&lt;/code&gt; in your browser, and you’ll see the sign-in link.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2F2d646fd91d3cfbc8246aa738c51ff808bfe1ddd5%2F5435f%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fclick-to-sign-in-f43d2da3f04c26caf928b8941e91f659f0179f09c29f2fa206a3a2cec0e4b49a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd33wubrfki0l68.cloudfront.net%2F2d646fd91d3cfbc8246aa738c51ff808bfe1ddd5%2F5435f%2Fassets-jekyll%2Fblog%2Foauth-implicit-flow-dead%2Fclick-to-sign-in-f43d2da3f04c26caf928b8941e91f659f0179f09c29f2fa206a3a2cec0e4b49a.png" alt="Click to sign in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on that link, and you’ll be redirected to Okta. If you’re already signed in, you’ll be immediately redirected, and the app will get an access token!&lt;/p&gt;

&lt;p&gt;Congrats! You’ve successfully implemented PKCE in a browser with vanilla JavaScript!&lt;/p&gt;

&lt;p&gt;You can find the completed sample code here: &lt;a href="https://github.com/aaronpk/pkce-vanilla-js" rel="noopener noreferrer"&gt;pkce-vanilla-js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully, this has been a helpful demonstration of what it takes to do PKCE in a browser! In practice, you’ll probably use a JavaScript library that handles this behind the scenes for you, but it can still be useful to know how this works under the hood!&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More about OAuth 2.0, the Implicit Flow, and Secure Authentication
&lt;/h2&gt;

&lt;p&gt;If you’d like to dig deeper into these topics, here are a few resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aaronpk/pkce-vanilla-js" rel="noopener noreferrer"&gt;Source code from this blog post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oauth.com/playground/authorization-code-with-pkce.html" rel="noopener noreferrer"&gt;Interactive demo of PKCE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.oauth.com/playground/implicit.html" rel="noopener noreferrer"&gt;Interactive demo of Implicit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2019/01/22/oauth-api-keys-arent-safe-in-mobile-apps"&gt;Why API Keys aren’t Safe in Mobile Apps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like what you learned today? Follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, and subscribe to our &lt;a href="https://www.youtube.com/channel/UC5AMiWqFVFxF1q9Ya1FuZ_Q" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; for more awesome content!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>pkce</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Use nginx to Add Authentication to Any Application</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Tue, 28 Aug 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/use-nginx-to-add-authentication-to-any-application-4b1o</link>
      <guid>https://forem.com/oktadev/use-nginx-to-add-authentication-to-any-application-4b1o</guid>
      <description>&lt;p&gt;Ever found yourself wanting to put an application behind a login form, but dreading writing all that code to deal with OAuth 2.0 or passwords? In this tutorial, I’ll show you how to use the nginx &lt;code&gt;auth_request&lt;/code&gt; module to protect any application running behind your nginx server with OAuth 2.0, without writing any code! Lasso, a microservice written in Go, handles the OAuth dance to any number of different auth providers so you don’t have to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Authenticate at the Web Server?
&lt;/h2&gt;

&lt;p&gt;Imagine you use nginx to run a small private wiki for your team. At first, you probably start out with adding a wiki user account for each person. It’s not too bad, adding new accounts for new hires, and removing them when they leave.&lt;/p&gt;

&lt;p&gt;A few months later, as your team and company start growing, you add some server monitoring software, and you want to put that behind a login so only your company can view it. Since it’s not very sophisticated software, the easiest way to do that is to create a single password for everyone in an &lt;code&gt;.htpasswd&lt;/code&gt; file, and share that user with the office.&lt;/p&gt;

&lt;p&gt;Another month goes by, and you add a continuous integration system, and that comes with GitHub authentication as an option, which seems reasonable since most of your team has GitHub accounts already.&lt;/p&gt;

&lt;p&gt;At this point, when someone new joins, you have to create a wiki account for them, add them to the GitHub organization, and give them the shared password for the other system. When someone leaves, you can delete their wiki account and remove them from GitHub, but let’s face it, you probably won’t change the shared password for a while since it’s annoying having to distribute that to everyone again.&lt;/p&gt;

&lt;p&gt;Surely there must be a better way to integrate all these systems to use a common shared login system! The problem is the wiki is written in PHP, the server monitoring system just ends up publishing a folder of static HTML, and the CI system is written in Ruby which only one person on your team feels comfortable writing.&lt;/p&gt;

&lt;p&gt;If the web server could handle authenticating users, then each backend system wouldn’t need to worry about it, since the only requests that could make it through would already be authenticated!&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the nginx auth_request Module
&lt;/h2&gt;

&lt;p&gt;Enter the nginx &lt;code&gt;auth_request&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;This module is shipped with nginx, but requires enabling when you compile nginx. When you download the nginx source and compile, just include the &lt;code&gt;--with-http_auth_request_module&lt;/code&gt; flag along with any others that you use.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;auth_request&lt;/code&gt; module sits between the internet and your backend server that nginx passes requests onto, and any time a request comes in, it first forwards the request to a separate server to check whether the user is authenticated, and uses the HTTP response to decide whether to allow the request to continue to the backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SiTNKWOq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/nginx-auth-request/nginx_auth_request-084b8c2075a5fe1d45ca2ab2d6438b70902f3d5da95b7d9e67c4e060b1ffb7c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SiTNKWOq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/nginx-auth-request/nginx_auth_request-084b8c2075a5fe1d45ca2ab2d6438b70902f3d5da95b7d9e67c4e060b1ffb7c9.png" alt="Flowchart illustrating the nginx auth_request module" width="599" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram illustrates a request that comes in for the server name &lt;code&gt;stats.avocado.lol&lt;/code&gt;. First, nginx fires off a sub-request to &lt;code&gt;login.avocado.lol&lt;/code&gt; (1), and if the response (2) to that request returns HTTP 200, it then continues forwarding the request on to the backend &lt;code&gt;stats.avocado.lol.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing an Auth Proxy
&lt;/h2&gt;

&lt;p&gt;Since the nginx &lt;code&gt;auth_request&lt;/code&gt; module has no concept of users or how to authenticate anyone, we need something else in the mix that can actually handle logging users in. In the diagram above, this is illustrated by the server name &lt;code&gt;login.avocado.lol&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This server needs to handle an HTTP request and return HTTP 200 or 401 depending on whether the user is logged in. If the user is not logged in, it needs to know how to get them to log in and set a session cookie.&lt;/p&gt;

&lt;p&gt;To accomplish this, we’ll use the open source project “&lt;a href="https://github.com/LassoProject/Lasso"&gt;Lasso&lt;/a&gt;”. Lasso is written in Go, so it’s super easy to deploy. Everything can be configured via a single YAML file. Lasso can be configured to authenticate users via a variety of OAuth and OpenID Connect backends such as GitHub, Google, Okta or any other custom servers.&lt;/p&gt;

&lt;p&gt;We’ll come back to configuring Lasso in a few minutes, but for now, let’s continue on to set up your protected server in nginx.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Your Protected nginx Host
&lt;/h2&gt;

&lt;p&gt;Starting with a typical nginx server block, you just need to add a couple lines to enable the &lt;code&gt;auth_request&lt;/code&gt; module. Here is an example server block that should look similar to your own config. This example just serves a folder of static HTML files, but the same idea applies whether you’re passing the request on to a fastcgi backend or using &lt;code&gt;proxy_pass&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 443 ssl http2;
  server_name stats.avocado.lol;

  ssl_certificate /etc/letsencrypt/live/avocado.lol/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/avocado.lol/privkey.pem;

  root /web/sites/stats.avocado.lol;

  index index.html;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following to your existing &lt;code&gt;server&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Any request to this server will first be sent to this URL
auth_request /lasso-validate;

location = /lasso-validate {
    # This address is where Lasso will be listening on
proxy_pass http://127.0.0.1:9090/validate;
proxy_pass_request_body off; # no need to send the POST body

proxy_set_header Content-Length "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

# these return values are passed to the @error401 call
auth_request_set $auth_resp_jwt $upstream_http_x_lasso_jwt;
auth_request_set $auth_resp_err $upstream_http_x_lasso_err;
auth_request_set $auth_resp_failcount $upstream_http_x_lasso_failcount;
}

error_page 401 = @error401;

# If the user is not logged in, redirect them to Lasso's login URL
location @error401 {
return 302 https://login.avocado.lol/login?url=https://$http_host$request_uri&amp;amp;lasso-failcount=$auth_resp_failcount&amp;amp;X-Lasso-Token=$auth_resp_jwt&amp;amp;error=$auth_resp_err;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s look at what’s going on here. The first line, &lt;code&gt;auth_request /lasso-validate;&lt;/code&gt; is what enables this flow. This tells the &lt;code&gt;auth_request&lt;/code&gt; module to first send any request to this URL before deciding whether it’s allowed to continue to the backend server.&lt;/p&gt;

&lt;p&gt;The block &lt;code&gt;location = /lasso-validate&lt;/code&gt; captures that URL, and proxies it to the Lasso server that will be listening on port 9090. We don’t need to send the POST body to Lasso, since all we really care about is the cookie.&lt;/p&gt;

&lt;p&gt;The line &lt;code&gt;error_page 401 = @error401;&lt;/code&gt; tells nginx what to do if Lasso returns an HTTP 401 response, which is to pass it to the block defined by &lt;code&gt;location @error401&lt;/code&gt;. That block will redirect the user’s browser to Lasso’s login URL which will kick off the flow to the real authentication backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure a Server Block for Lasso
&lt;/h2&gt;

&lt;p&gt;Next, configure a new server block for Lasso so that it has a publicly accessible URL like &lt;code&gt;https://login.avocado.lol&lt;/code&gt;. All this needs to do is proxy the request to the backend Lasso server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server {
  listen 443 ssl;
  server_name login.avocado.lol;

  ssl_certificate /etc/letsencrypt/live/login.avocado.lol/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/login.avocado.lol/privkey.pem;

  # Proxy to your Lasso instance
  location / {
    proxy_set_header Host login.avocado.lol;
    proxy_set_header X-Forwarded-Proto https;
    proxy_pass http://127.0.0.1:9090;
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure and Deploy Lasso
&lt;/h2&gt;

&lt;p&gt;You’ll need to download &lt;a href="https://github.com/LassoProject/lasso"&gt;Lasso&lt;/a&gt; and compile the Go binary for your platform. You can follow the instructions in the project’s README file.&lt;/p&gt;

&lt;p&gt;Once you’ve got a binary, you’ll need to create the config file to define the way you want Lasso to authenticate users.&lt;/p&gt;

&lt;p&gt;Copy &lt;code&gt;config/config.yml_example&lt;/code&gt; to &lt;code&gt;config/config.yml&lt;/code&gt; and read through the settings there. Most of the defaults will be fine, but you’ll want to create your own JWT secret string and replace the placeholder value of &lt;code&gt;your_random_string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The easiest way to configure Lasso is to have it allow any user that can authenticate at the OAuth server be allowed to access the backend. This works great if you’re using a private OAuth server like Okta to manage your users. Go ahead and set &lt;code&gt;allowAllUsers: true&lt;/code&gt; to enable this behavior, and comment out the &lt;code&gt;domains:&lt;/code&gt; chunk.&lt;/p&gt;

&lt;p&gt;You’ll need to choose an OAuth 2.0 provider to use to actually authenticate users. In this example we’ll use Okta, since that’s the easiest way to have a full OAuth/OpenID Connect server and be able to manage all your user accounts from a single dashboard. Before you can finish filling out the config file, you’ll need to sign up for an Okta Developer account at &lt;a href="https://developer.okta.com/"&gt;developer.okta.com/&lt;/a&gt;. Once you create an account, click &lt;strong&gt;Applications&lt;/strong&gt; in the top menu, and create a new application. Choose &lt;strong&gt;Web&lt;/strong&gt; as the application platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PIpzFcQ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/nginx-auth-request/okta-create-app-a16ef6d91a90289f62f0b1ccd955b5e86e215d31c56e8be536485055d194eb86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PIpzFcQ5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/nginx-auth-request/okta-create-app-a16ef6d91a90289f62f0b1ccd955b5e86e215d31c56e8be536485055d194eb86.png" alt="Create a web application with Okta" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next screen, you’ll need to configure the &lt;strong&gt;Base URI&lt;/strong&gt; and &lt;strong&gt;Login redirect URI&lt;/strong&gt; to match your own server’s settings. Lasso’s redirect URI ends in &lt;code&gt;/auth&lt;/code&gt; so your configuration should look like the below screenshot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S3RLhU0H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/nginx-auth-request/okta-configure-app-20a27af52e6acb17ae07596c298cd28c6c95342684faf94c2b1dcf15e8c6bb37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S3RLhU0H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/nginx-auth-request/okta-configure-app-20a27af52e6acb17ae07596c298cd28c6c95342684faf94c2b1dcf15e8c6bb37.png" alt="Create a web application with Okta" width="735" height="811"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve done that, Okta will give you a client ID and secret, which you’ll need to include in the config file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;config.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;oauth:
  provider: oidc
  client_id: {yourClientID}
  client_secret: {yourClientSecret}
  auth_url: https://{yourOktaDomain}/oauth2/default/v1/authorize
  token_url: https://{yourOktaDomain}/oauth2/default/v1/token
  user_info_url: https://{yourOktaDomain}/oauth2/default/v1/userinfo
  scopes:
    - openid
    - email
  # Set the callback URL to the domain that Lasso is running on
  callback_url: https://login.avocado.lol/auth

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run Lasso! It will listen on port 9090, which is where you’ve configured nginx to send the &lt;code&gt;auth_request&lt;/code&gt; verifications as well as serve traffic from &lt;code&gt;login.avocado.lol&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you reload the nginx config, all requests to &lt;code&gt;stats.avocado.lol&lt;/code&gt; will require that you log in via Okta first!&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Who Logged In?
&lt;/h2&gt;

&lt;p&gt;If you’re putting a dynamic web app behind nginx and you care not only about &lt;em&gt;whether&lt;/em&gt; someone was able to log in, but also &lt;em&gt;who they are&lt;/em&gt;, there is one more trick we can use.&lt;/p&gt;

&lt;p&gt;By default, Lasso will extract a user ID via OpenID Connect (or GitHub or Google if you’ve configured those as your auth providers), and will include that user ID in an HTTP header that gets passed back up to the main server.&lt;/p&gt;

&lt;p&gt;In your main server block, just below the line &lt;code&gt;auth_request /lasso-validate;&lt;/code&gt; which enables the &lt;code&gt;auth_request&lt;/code&gt; module, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;auth_request_set $auth_user $upstream_http_x_lasso_user;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will take the HTTP header that Lasso sets, &lt;code&gt;X-Lasso-User&lt;/code&gt;, and assign it to the nginx variable &lt;code&gt;$auth_user&lt;/code&gt;. Then, depending on whether you use fastcgi or proxy_pass, include one of the two lines below in your server block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fastcgi_param REMOTE_USER $auth_user;
proxy_set_header Remote-User $auth_user;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These will set an HTTP header with the value of &lt;code&gt;$auth_user&lt;/code&gt; that your backend server can read in order to know who logged in. For example, in PHP you can access this data using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
echo 'Hello, ' . $_SERVER['REMOTE_USER'] . '!';

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can be sure that your internal app can only be accessed by authenticated users!&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About OAuth 2.0 and Secure User Management with Okta
&lt;/h2&gt;

&lt;p&gt;For more information and tutorials about OAuth 2.0, check out some of our other blog posts!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2018/07/09/five-minute-php-app-auth"&gt;Add Authentication to your PHP App in 5 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2018/04/10/oauth-authorization-code-grant-type"&gt;What is the OAuth 2.0 Authorization Code Grant Type?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2018/05/24/what-is-the-oauth2-implicit-grant-type"&gt;What is the OAuth 2.0 Implicit Grant Type?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, we’d love to hear from you about this post, or really anything else! Hit us up in the comments, or on Twitter &lt;a href="https://twitter.com/OktaDev"&gt;@oktadev&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>nginx</category>
      <category>sso</category>
      <category>oauth</category>
      <category>proxy</category>
    </item>
    <item>
      <title>OAuth 2.0 from the Command Line</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Mon, 16 Jul 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/oauth-20-from-the-command-line-4d15</link>
      <guid>https://forem.com/oktadev/oauth-20-from-the-command-line-4d15</guid>
      <description>&lt;p&gt;So you’ve found yourself writing a command line script and needing to talk to an API that uses OAuth 2.0? The typical approaches to getting an OAuth access token from a command line script usually involve copying and pasting the authorization code into the terminal. But we can do better!&lt;/p&gt;

&lt;p&gt;In this tutorial, I’ll show you how to write a command line script which is able to complete the OAuth exchange all without any copying and pasting long strings! Why? Because it’s mildly useful, but most importantly, because it’s fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started with Okta
&lt;/h2&gt;

&lt;p&gt;We’re going to write this sample app to talk to the Okta API, but it should be easily adapted to any OAuth 2.0 service you’re using. To get started, &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;sign up for a free developer account&lt;/a&gt;, and come back here when you’ve made your account.&lt;/p&gt;

&lt;p&gt;Why Okta? Well, because Okta is a free-to-use API service that stores user accounts, and makes handling user authentication, authorization, social login, password reset, etc. — simple. Okta utilizes open standards like OAuth 2.0 to make integration seamless.&lt;/p&gt;

&lt;p&gt;We first need to create an OAuth application in the Okta Developer dashboard. In the Applications section of your account, click &lt;strong&gt;Add Application&lt;/strong&gt; , and choose &lt;strong&gt;Web&lt;/strong&gt;. (Yes I realize this is counterintuitive, but choosing &lt;strong&gt;Web&lt;/strong&gt; is what tells Okta that we want to do that OAuth &lt;a href="https://dev.to/oktadev/what-is-the-oauth-20-authorization-code-grant-type-368m"&gt;Authorization Code flow&lt;/a&gt;.) You can accept all the defaults in the application settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Fcreate-app-e26389f3c54b648f687e07f380153ee1cd74f1c3b229e4c814eabab1d5775c4c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Fcreate-app-e26389f3c54b648f687e07f380153ee1cd74f1c3b229e4c814eabab1d5775c4c.png" alt="Create an application on Okta"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and you’ll be taken to the next screen where you can get your new client ID and secret. Copy those two values and enter them in the code below, adding this to a new PHP file called &lt;code&gt;login.php&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
$client_id = '{yourClientId}';
$client_secret = '{yourClientSecret}';

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to find the authorization server metadata URL. From the top menu, choose &lt;strong&gt;API&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Authorization Servers&lt;/strong&gt;. You should see one authorization server in the list, &lt;code&gt;default&lt;/code&gt;. Click that and fill in the Metadata URI into your PHP file like the below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$metadata = http('https://{yourOktaDomain}/oauth2/default/.well-known/oauth-authorization-server');

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Trick to OAuth 2.0 on the Command Line
&lt;/h2&gt;

&lt;p&gt;The way we’re going to avoid the need to copy and paste anything during the login flow is by having our PHP command line script start a mini HTTP server just when we need it, and shut down when we’re done.&lt;/p&gt;

&lt;p&gt;The script will launch the browser to the authorization URL, and when Okta redirects the user back to the mini built-in server, we’ll catch that response, extract the authorization code, shut down the server, and continue with whatever the script was doing.&lt;/p&gt;

&lt;p&gt;To begin, we need to define a few variables that we’ll use when setting up this server, as well as define a function that will help us make HTTP requests. Copy the following code into your PHP file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ip = '127.0.0.1';
$port = '8080';

$redirect_uri = 'http://'.$ip.':'.$port.'/authorization-code/callback';
$socket_str = 'tcp://'.$ip.':'.$port;

function http($url, $params=false) {
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  if($params)
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
  return json_decode(curl_exec($ch));
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start the OAuth 2.0 Flow
&lt;/h2&gt;

&lt;p&gt;We’re ready to start the OAuth flow now. First we generate a random “state” value for added security. Since we’re building this in a command line script, we don’t need to worry about storing it in a session or anything, since we’ll generate it and then use it and then be done with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$state = bin2hex(random_bytes(5));

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we can build the authorization URL that we’ll open to start the flow, using the &lt;code&gt;authorization_endpoint&lt;/code&gt; from the server’s metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$authorize_url = $metadata-&amp;gt;authorization_endpoint.'?'.http_build_query([
  'response_type' =&amp;gt; 'code',
  'client_id' =&amp;gt; $client_id,
  'redirect_uri' =&amp;gt; $redirect_uri,
  'state' =&amp;gt; $state,
]);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far this is a typical OAuth request, nothing particularly unique happening here yet.&lt;/p&gt;

&lt;p&gt;Since we’ll be running this from the command line, we obviously can’t use the normal technique of sending an HTTP redirect to the browser, since we aren’t in a browser! Instead, we need to use a shell command to launch a new browser to the URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "Open the following URL in a browser to continue\n";
echo $authorize_url."\n";
shell_exec("open '".$authorize_url."'");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On a Mac, &lt;code&gt;open&lt;/code&gt; will try to open whatever argument is passed to it using the system default handler. Since we give it a URL, it will open a browser window to that URL. If you’re not on a mac, then you’ll have to click the URL that is displayed in the terminal instead.&lt;/p&gt;

&lt;p&gt;Now here comes the trick. The script just launched a browser window to the authorization server, and the user now has to log in. After they do, that browser window will be redirected back to &lt;code&gt;http://127.0.0.1:8080/authorization-code/callback&lt;/code&gt; with an authorization code in the query string. This means we need to have an HTTP server ready to handle that request so that we can extract the authorization code from the URL.&lt;/p&gt;

&lt;p&gt;So we’re going to create a mini HTTP server in our command line script. It will open a socket on port 8080, wait for a complete HTTP request, send back a simple response, and return the authorization code that was in the query string. Here’s a bit of code that will do this, adapted from a real command line tool that does this written by &lt;a href="http://cweiske.de/shpub.htm" rel="noopener noreferrer"&gt;Christian Weiske&lt;/a&gt;. Add the function below into your PHP file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function startHttpServer($socketStr) {
  // Adapted from http://cweiske.de/shpub.htm

  $responseOk = "HTTP/1.0 200 OK\r\n"
    . "Content-Type: text/plain\r\n"
    . "\r\n"
    . "Ok. You may close this tab and return to the shell.\r\n";
  $responseErr = "HTTP/1.0 400 Bad Request\r\n"
    . "Content-Type: text/plain\r\n"
    . "\r\n"
    . "Bad Request\r\n";

  ini_set('default_socket_timeout', 60 * 5);

  $server = stream_socket_server($socketStr, $errno, $errstr);

  if(!$server) {
    Log::err('Error starting HTTP server');
    return false;
  }

  do {
    $sock = stream_socket_accept($server);
    if(!$sock) {
      Log::err('Error accepting socket connection');
      exit(1);
    }
    $headers = [];
    $body = null;
    $content_length = 0;
    //read request headers
    while(false !== ($line = trim(fgets($sock)))) {
      if('' === $line) {
        break;
      }
      $regex = '#^Content-Length:\s*([[:digit:]]+)\s*$#i';
      if(preg_match($regex, $line, $matches)) {
        $content_length = (int)$matches[1];
      }
      $headers[] = $line;
    }
    // read content/body
    if($content_length &amp;gt; 0) {
      $body = fread($sock, $content_length);
    }
    // send response
    list($method, $url, $httpver) = explode(' ', $headers[0]);
    if($method == 'GET') {
      #echo "Redirected to $url\n";
      $parts = parse_url($url);
      #print_r($parts);
      if(isset($parts['path']) &amp;amp;&amp;amp; $parts['path'] == '/authorization-code/callback'
        &amp;amp;&amp;amp; isset($parts['query'])
      ) {
        parse_str($parts['query'], $query);
        if(isset($query['code']) &amp;amp;&amp;amp; isset($query['state'])) {
          fwrite($sock, $responseOk);
          fclose($sock);
          return $query;
        }
      }
    }
    fwrite($sock, $responseErr);
    fclose($sock);
  } while (true);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use this function to start a server and wait for the browser to hit it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Start the mini HTTP server and wait for their browser to hit the redirect URL
// Store the query string parameters in a variable
$auth = startHttpServer($socket_str);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Fstart-login-b3babdb83ba4241fe5ca60267d2305f17d81a9f07b98ae22792af0f114a598c1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Fstart-login-b3babdb83ba4241fe5ca60267d2305f17d81a9f07b98ae22792af0f114a598c1.png" alt="Start the login from the command line"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle the Authorization Response
&lt;/h2&gt;

&lt;p&gt;At this point, after the user logs in, their browser will be redirected to &lt;code&gt;http://127.0.0.1:8080/authorization-code/callback?code=XXXX&amp;amp;state=YYYY&lt;/code&gt;. Our built-in web server will look at the URL of the request and extract the code and state parameters. We need to double check that the state parameter matches the one we set at the beginning, and then we can use the code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Fbrowser-redirect-6171f9498f67d8418ffed7646fb627267f32300e4168a0a9af88a62d0f2f8024.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Fbrowser-redirect-6171f9498f67d8418ffed7646fb627267f32300e4168a0a9af88a62d0f2f8024.png" alt="Handling the browser redirect"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if($auth['state'] != $state) {
  echo "Wrong 'state' parameter returned\n";
  exit(2);
}

$code = $auth['code'];

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here out, we’re proceeding with the normal OAuth Authorization Code request just like any other app. We make a POST request to the token endpoint to exchange the authorization code for an access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "Getting an access token...\n";
$response = http($metadata-&amp;gt;token_endpoint, [
  'grant_type' =&amp;gt; 'authorization_code',
  'code' =&amp;gt; $code,
  'redirect_uri' =&amp;gt; $redirect_uri,
  'client_id' =&amp;gt; $client_id,
  'client_secret' =&amp;gt; $client_secret,
]);

if(!isset($response-&amp;gt;access_token)) {
  echo "Error fetching access token\n";
  exit(2);
}

$access_token = $response-&amp;gt;access_token;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have an access token in &lt;code&gt;$access_token&lt;/code&gt;! If this were a real tool, you’d probably want to store that somewhere your script can find it next time it’s run. But for the purposes of this demo, we won’t store it anywhere. Instead, we’ll make a request to find out the username of who just logged in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "Getting the username...\n";
$token = http($metadata-&amp;gt;introspection_endpoint, [
  'token' =&amp;gt; $access_token,
  'client_id' =&amp;gt; $client_id,
  'client_secret' =&amp;gt; $client_secret,
]);

if($token-&amp;gt;active == 1) {
  echo "Logged in as ".$token-&amp;gt;username."\n";
  die();
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes a request to the token introspection endpoint to find the username of the person who logged in, prints it to the terminal, and quits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Flogged-in-45a2aea29c703ce80d264c2d2275f7e81265b03235849a340d97e1a67abca8b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-2-command-line%2Flogged-in-45a2aea29c703ce80d264c2d2275f7e81265b03235849a340d97e1a67abca8b6.png" alt="Logged in on the command line"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it! You can open a terminal and run this code with the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php login.php

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the full source code for this application on GitHub at &lt;a href="https://github.com/aaronpk/command-line-oauth" rel="noopener noreferrer"&gt;https://github.com/aaronpk/command-line-oauth&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About OAuth 2.0 and Secure User Management with Okta
&lt;/h2&gt;

&lt;p&gt;For more information and tutorials about OAuth 2.0, check out some of our other blog posts!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/07/09/five-minute-php-app-auth" rel="noopener noreferrer"&gt;Add Authentication to your PHP App in 5 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" rel="noopener noreferrer"&gt;What is the OAuth 2.0 Authorization Code Grant Type?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/05/24/what-is-the-oauth2-implicit-grant-type" rel="noopener noreferrer"&gt;What is the OAuth 2.0 Implicit Grant Type?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com//blog/2018/06/14/php-crud-app-symfony-vue" rel="noopener noreferrer"&gt;Build a Basic CRUD App with Symfony 4 and Vue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, we’d love to hear from you about this post, or really anything else! Hit us up in the comments, or on Twitter &lt;a href="https://twitter.com/OktaDev" rel="noopener noreferrer"&gt;@oktadev&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>security</category>
      <category>php</category>
    </item>
    <item>
      <title>Add Authentication to your PHP App in 5 Minutes</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Mon, 09 Jul 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/add-authentication-to-your-php-app-in-5-minutes-5e04</link>
      <guid>https://forem.com/oktadev/add-authentication-to-your-php-app-in-5-minutes-5e04</guid>
      <description>&lt;p&gt;Have you ever found yourself building an app and needing to add authentication, dreading the thought of setting up yet another username and password database? In this post, I’ll show you how easy it is to use &lt;a href="https://developer.okta.com/" rel="noopener noreferrer"&gt;Okta&lt;/a&gt; to add authentication to a simple PHP app in 5 minutes. By leveraging Okta’s simple OAuth API, we can breeze past most of the challenges involved in authenticating users by letting Okta take care of the hard parts.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/o7JW5uPDc5w"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;To follow this tutorial, you’ll first need an Okta Developer account if you don’t yet have an account, &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;sign up for free&lt;/a&gt; and come back here when you’re done. We won’t use any external PHP libraries or dependencies in this example just to keep things simple.&lt;/p&gt;

&lt;p&gt;We’ll start with a single PHP file to demonstrate the logged in/logged out state of our application. Then we’ll integrate the &lt;a href="https://developer.okta.com/product/authentication/" rel="noopener noreferrer"&gt;Okta API&lt;/a&gt; to authenticate users and find their username after they’re logged in. You can use this guide as the basis of adding authentication to your own real application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up the Sample PHP App
&lt;/h2&gt;

&lt;p&gt;If you want to skip to the finished project, check out the &lt;a href="https://github.com/aaronpk/quick-php-authentication" rel="noopener noreferrer"&gt;source code on GitHub&lt;/a&gt;. This post builds up the code in the finished project and explains it step by step.&lt;/p&gt;

&lt;p&gt;Create a new file, &lt;code&gt;index.php&lt;/code&gt;, with the following contents. This will set up two different “views” of our application based on whether the user is logged in (whether there is a username in the PHP session).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="c1"&gt;// Begin the PHP session so we have a place to store the username&lt;/span&gt;
&lt;span class="nb"&gt;session_start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// If there is a username, they are logged in, and we'll show the logged-in view&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;p&amp;gt;Logged in as&amp;lt;/p&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;p&amp;gt;'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;/p&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;p&amp;gt;&amp;lt;a href="/?logout"&amp;gt;Log Out&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// If there is no username, they are logged out, so show them the login link&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$authorize_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'TODO'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;p&amp;gt;Not logged in&amp;lt;/p&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;p&amp;gt;&amp;lt;a href="'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$authorize_url&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'"&amp;gt;Log In&amp;lt;/a&amp;gt;&amp;lt;/p&amp;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;p&gt;With that simple skeleton created, we have a place to start working on adding authentication. This app now looks for a “username” in the session variable and considers the user logged in when it’s set.&lt;/p&gt;

&lt;p&gt;Next, let’s add a simple function that we’ll use when making API calls to Okta. This function will make an HTTP request and return the JSON-decoded response. It takes a URL and optionally an array of parameters. If there are parameters, it will make a POST request with the parameters as the HTTP body. Otherwise it makes a GET request to the given URL. Since all the API calls we’re doing will result in a JSON response body, this function decodes the JSON response and returns the resulting object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;curl_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;CURLOPT_RETURNTRANSFER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;curl_setopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;CURLOPT_POSTFIELDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;http_build_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;curl_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ch&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;h2&gt;
  
  
  Create an OAuth Application in Okta
&lt;/h2&gt;

&lt;p&gt;Before we can get much further, we need to configure our Okta Developer account to get a client ID and secret to use to talk to the API. In the Applications section of your Okta Developer account, click &lt;strong&gt;Add Application **, and choose **Web&lt;/strong&gt;. The only change we need to make to the default application settings is changing the callback URL to &lt;code&gt;http://localhost:8080/&lt;/code&gt;, since we’re writing the entire flow in this one PHP file.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feekyjspj9um4ioqiybnd.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feekyjspj9um4ioqiybnd.png" alt="Create an application on Okta" width="736" height="813"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; and you’ll be taken to the next screen where you can get your new client ID and secret. Copy those two values into the variables below, and add this chunk to the top of your PHP file, right after &lt;code&gt;session_start()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$client_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$client_secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$redirect_uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'http://localhost:8080/'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also need to find the authorization server metadata URL. From the top menu, choose &lt;strong&gt;API&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Authorization Servers&lt;/strong&gt;. You should see one authorization server in the list, &lt;code&gt;default&lt;/code&gt;. Click that and copy the Metadata URI below the client and redirect lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$metadata_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://{yourOktaOrg}/oauth2/default/.well-known/oauth-authorization-server'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// Fetch the authorization server metadata which contains a few URLs&lt;/span&gt;
&lt;span class="c1"&gt;// that we need later, such as the authorization and token endpoints&lt;/span&gt;
&lt;span class="nv"&gt;$metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$metadata_url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build the Login URL
&lt;/h2&gt;

&lt;p&gt;Now we’re ready to start building the login URL where we can send the user to authenticate. Replace the line &lt;code&gt;$authorize_url = 'TODO';&lt;/code&gt; with the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;  &lt;span class="c1"&gt;// Generate a random state parameter for CSRF security&lt;/span&gt;
  &lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;bin2hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;random_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

  &lt;span class="c1"&gt;// Build the authorization URL by starting with the authorization endpoint&lt;/span&gt;
  &lt;span class="c1"&gt;// and adding a few query string parameters identifying this application&lt;/span&gt;
  &lt;span class="nv"&gt;$authorize_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$metadata&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;authorization_endpoint&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;'?'&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;http_build_query&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'response_type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'client_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'redirect_uri'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$redirect_uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'state'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s1"&gt;'scope'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'openid'&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;p&gt;This bit of code sets up the beginning of the OAuth Authorization Code flow. If you want more details about these parameters, I wrote about the Authorization Code flow previously on this blog: &lt;a href="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" rel="noopener noreferrer"&gt;What is the OAuth 2.0 Authorization Code Grant Type?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve got enough built now to try this out. From the command line, navigate to the folder with your &lt;code&gt;index.php&lt;/code&gt; file and start a PHP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-S&lt;/span&gt; 127.0.0.1:8080

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can visit this page in a browser &lt;a href="http://127.0.0.1:8080/" rel="noopener noreferrer"&gt;http://127.0.0.1:8080/&lt;/a&gt; and you’ll see your login prompt.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9x88kxfjsyk2sw3b7gj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk9x88kxfjsyk2sw3b7gj.png" alt="Login Prompt" width="300" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don’t click the link just yet, since we still need to set up handling the callback and getting an access token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle the OAuth Redirect
&lt;/h2&gt;

&lt;p&gt;When the user clicks the login URL, they’re sent to the Okta authorization server. The authorization server will ask them to log in (if they aren’t already logged in), and will then generate a temporary authorization code and redirect the user back to this application. To verify that the user did in fact log in, the application needs to check that this temporary authorization code is valid by exchanging it for an access token at Okta’s authorization server.&lt;/p&gt;

&lt;p&gt;Between your client ID configuration lines and the section that renders the logged-out view, we’re going to add a new section that handles exchanging the authorization code for an access token.&lt;/p&gt;

&lt;p&gt;Let’s start by adding a check for the authorization code in the query string. Your code should look something like this now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nv"&gt;$metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$metadata_url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// TODO: we'll work on filling out this section next&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside this new section, in place of the “TODO” comment we just added, let’s first add a few bits of error checking. We’ll start by checking that the authorization server returned the same state parameter we set when the user started logging in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'state'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'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;die&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Authorization server returned an invalid state parameter'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'error'&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Authorization server returned an error: '&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;htmlspecialchars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'error'&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;p&gt;It’s also possible that the authorization server returns an error here, so we’ll display the error if that happens.&lt;/p&gt;

&lt;p&gt;Next, we need to take the authorization code from the URL and exchange it for an access token at the token endpoint. To do this, we use the token endpoint from the metadata response, and include our client ID and secret in the API call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;  &lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$metadata&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;token_endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'grant_type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'authorization_code'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'code'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$_GET&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'code'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s1"&gt;'redirect_uri'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$redirect_uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'client_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'client_secret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$client_secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;isset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Error fetching access token'&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;p&gt;If all goes well, we’ll end up with an access token in the &lt;code&gt;$response&lt;/code&gt; object. We don’t actually need the access token for anything except finding out who logged in, so we won’t be storing it anywhere. Instead, we’ll use it to make a request to the token introspection endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;  &lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$metadata&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;introspection_endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'token'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'client_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$client_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'client_secret'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$client_secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$_SESSION&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Location: /'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;die&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;p&gt;This code takes the access token and sends it, along with the client credentials, to the token introspection endpoint. The introspection endpoint tells us the username of the person who logged in. If the token is active, we set the username in the session, then redirect back to the home page. Now that the username is in the session, our “app” considers the user logged in and we see the logged-in page with the user’s email address!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fak2y3ondt8lpzgmr5xy6.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fak2y3ondt8lpzgmr5xy6.png" alt="Logged in!" width="293" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hopefully this has been a helpful illustration of how easy it is to add authentication to a simple PHP app! Obviously this is a minimalist example, and in reality your application is much more featureful and probably better organized into more than one file. But you should be able to take what you’ve learned here and adapt it to other frameworks or use cases that you’re working with!&lt;/p&gt;

&lt;p&gt;You can see the full source code for this application on &lt;a href="https://github.com/aaronpk/quick-php-authentication" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;For more information and tutorials about OAuth, check out some of our other blog posts!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" rel="noopener noreferrer"&gt;What is the OAuth 2.0 Authorization Code Grant Type?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/05/24/what-is-the-oauth2-implicit-grant-type" rel="noopener noreferrer"&gt;What is the OAuth 2.0 Implicit Grant Type?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/06/14/php-crud-app-symfony-vue" rel="noopener noreferrer"&gt;Build a Basic CRUD App with Symfony 4 and Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2017/03/21/spring-boot-oauth" rel="noopener noreferrer"&gt;Get Started with Spring Boot, OAuth 2.0, and Okta&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, we’d love to hear from you about this post, or really anything else! Hit us up in the comments, or on Twitter &lt;a href="https://twitter.com/OktaDev" rel="noopener noreferrer"&gt;@oktadev&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>php</category>
      <category>oauth</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What is the OAuth 2.0 Implicit Grant Type?</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Thu, 24 May 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/what-is-the-oauth-20-implicit-grant-type-586m</link>
      <guid>https://forem.com/oktadev/what-is-the-oauth-20-implicit-grant-type-586m</guid>
      <description>&lt;p&gt;The Implicit Grant Type is a way for a single-page JavaScript app to get an access token without an intermediate code exchange step. It was originally created for use by JavaScript apps (which don’t have a way to safely store secrets) but is generally no longer recommended.&lt;/p&gt;

&lt;p&gt;This post is the second in a series where we explore frequently used OAuth 2.0 grant types. Previously we covered the &lt;a href="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" rel="noopener noreferrer"&gt;Authorization Code&lt;/a&gt; grant type. If you want to back up a bit and learn more about OAuth 2.0 before we get started, check out &lt;a href="https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth" rel="noopener noreferrer"&gt;What the Heck is OAuth?&lt;/a&gt;, also on the Okta developer blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an OAuth 2.0 Grant Type?
&lt;/h2&gt;

&lt;p&gt;In OAuth 2.0, the term “grant type” refers to the way an application gets an access token. OAuth 2.0 defines several grant types, including the authorization code flow. OAuth 2.0 extensions can also define new grant types.&lt;/p&gt;

&lt;p&gt;Each grant type is optimized for a particular use case, whether that’s a web app, a native app, a device without the ability to launch a web browser, or server-to-server applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Implicit Grant
&lt;/h2&gt;

&lt;p&gt;Like the &lt;a href="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" rel="noopener noreferrer"&gt;Authorization Code Grant Type&lt;/a&gt;, the Implicit Grant starts out by building a link and directing the user’s browser to that URL. At a high level, the flow has the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application opens a browser to send the user to the OAuth server&lt;/li&gt;
&lt;li&gt;The user sees the authorization prompt and approves the app’s request&lt;/li&gt;
&lt;li&gt;The user is redirected back to the application with an access token in the URL fragment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Get the User’s Permission
&lt;/h3&gt;

&lt;p&gt;OAuth is all about enabling users to grant limited access to applications. The application first needs to decide which permissions it is requesting, then send the user to a browser to get their permission. To begin the Implicit flow, the application constructs a URL like the following and directs the browser to that URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://authorization-server.com/auth
 ?response_type=token
 &amp;amp;client_id=29352910282374239857
 &amp;amp;redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
 &amp;amp;scope=create+delete
 &amp;amp;state=xcoiv98y3md22vwsuye3kch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s each query parameter explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;response_type=token&lt;/code&gt;&lt;/strong&gt; - This tells the authorization server that the application is initiating the Implicit flow. Note the difference from the Authorization Code flow where this value is set to &lt;code&gt;code&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_id&lt;/code&gt; - The public identifier for the application, obtained when the developer first registered the application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect_uri&lt;/code&gt; - Tells the authorization server where to send the user back to after they approve the request.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scope&lt;/code&gt; - One or more space-separated strings indicating which permissions the application is requesting. The specific OAuth API you’re using will define the scopes that it supports.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt; - The application generates a random string and includes it in the request. It should then check that the same value is returned after the user authorizes the app. This is used to prevent CSRF attacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the user visits this URL, the authorization server will present them with a prompt asking if they would like to authorize this application’s request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-authorization-code-grant-type%2Foauth-prompt-6489c6516fda5e0deea637d96f8398683fea6ade6054ee779e306e0b8ac5dcb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Foauth-authorization-code-grant-type%2Foauth-prompt-6489c6516fda5e0deea637d96f8398683fea6ade6054ee779e306e0b8ac5dcb8.png" alt="OAuth Prompt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Redirect Back to the Application
&lt;/h2&gt;

&lt;p&gt;If the user approves the request, the authorization server will redirect the browser back to the &lt;code&gt;redirect_uri&lt;/code&gt; specified by the application, adding a &lt;code&gt;token&lt;/code&gt; and &lt;code&gt;state&lt;/code&gt; to the fragment part of the URL.&lt;/p&gt;

&lt;p&gt;For example, the user will be redirected back to a URL such as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example-app.com/redirect
  #access_token=g0ZGZmNj4mOWIjNTk2Pw1Tk4ZTYyZGI3
  &amp;amp;token_type=Bearer
  &amp;amp;expires_in=600
  &amp;amp;state=xcoVv98y2kd44vuqwye3kcq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the two major differences between this and the Authorization Code flow: the access token is returned instead of the temporary code, and both values are returned in the URL fragment (after the &lt;code&gt;#&lt;/code&gt;) instead of in the query string. By doing this, the server ensures that the app will be able to access the value from the URL, but the browser won’t send the access token in the HTTP request back to the server.&lt;/p&gt;

&lt;p&gt;The state value will be the same value that the application initially set in the request. The application is expected to check that the state in the redirect matches the state it originally set. This protects against CSRF and other related attacks.&lt;/p&gt;

&lt;p&gt;The server will also indicate the lifetime of the access token before it expires. This is usually a very short amount of time, along the lines of 5 to 10 minutes, because of the additional risk in returning the token in the URL itself.&lt;/p&gt;

&lt;p&gt;This token is ready to go! There is no additional step before the app can start using it!&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use the Implicit Grant Type
&lt;/h2&gt;

&lt;p&gt;In general, there are extremely limited circumstances in which it makes sense to use the Implicit grant type. The Implicit grant type was created for JavaScript apps while trying to also be easier to use than the Authorization Code grant. In practice, any benefit gained from the initial simplicity is lost in the other factors required to make this flow secure. Instead, JavaScript apps should use the Authorization Code grant without the client secret.&lt;/p&gt;

&lt;p&gt;The main downside to the Implicit grant type is that the access token is returned in the URL directly, rather than being returned via a trusted back channel like in the &lt;a href="https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type" rel="noopener noreferrer"&gt;Authorization Code&lt;/a&gt; flow. The access token itself will be logged in the browser’s history, so most servers issue short-lived access tokens to mitigate the risk of the access token being leaked. Because there is no backchannel, the Implicit flow also does not return a refresh token. In order for the application to get a new access token when the short-lived one expires, the application has to either send the user back through the OAuth flow again, or use tricks such as hidden iframes, adding back complexity that the flow was originally created to avoid.&lt;/p&gt;

&lt;p&gt;One of the historical reasons that the Implicit flow used the URL fragment is that browsers could manipulate the fragment part of the URL without triggering a page reload. However, the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API" rel="noopener noreferrer"&gt;History API&lt;/a&gt; now means that browsers can update the full path and query string of the URL without a page reload, so this is no longer an advantage of the Implicit flow.&lt;/p&gt;

&lt;p&gt;The one remaining reason to use the Implicit flow is if the authorization server doesn’t or can’t support cross-origin requests (CORS). The Authorization Code grant requires that the JavaScript app make a POST request to the authorization server, so the authorization server will need to support the appropriate CORS headers in order to allow the browser to make that request. This is a relatively easy change to make if you’re building your own authorization server, but if you are using an existing server then you may be stuck using the Implicit grant to get around the CORS limitation.&lt;/p&gt;

&lt;p&gt;For more details and links to additional research and documentation of these limitations, check out the &lt;a href="https://oauth.net/2/grant-types/implicit/" rel="noopener noreferrer"&gt;Implicit Grant Type&lt;/a&gt; on oauth.net.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Implicit Grant Type and OpenID Connect
&lt;/h3&gt;

&lt;p&gt;While we haven’t discussed OpenID Connect in this series yet, it’s worth pointing out one important point with regards to how the Implicit grant relates to OpenID Connect. (For some more background on OpenID Connect, see &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;An OpenID Connect Primer&lt;/a&gt; also on the Okta Developer blog.)&lt;/p&gt;

&lt;p&gt;In OpenID Connect, the server returns an &lt;code&gt;id_token&lt;/code&gt; in addition to the &lt;code&gt;access_token&lt;/code&gt; in the URL fragment. This is considered an insecure channel to transmit this data, as it can easily be tampered with. Since OpenID Connect ID tokens contain claims such as user identity, this token’s signature &lt;strong&gt;must&lt;/strong&gt; be verified before it can be trusted. Otherwise, the user could change the data in the token and potentially impersonate other users in the JavaScript app. In contrast, when the app uses the Authorization Code grant to obtain the &lt;code&gt;id_token&lt;/code&gt;, the token is sent over a secure HTTPS connection which provides a baseline level of security even if the token signature isn’t validated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About OAuth and Okta
&lt;/h2&gt;

&lt;p&gt;Try out a live demo of the Implicit grant type on the &lt;a href="https://www.oauth.com/playground/implicit.html" rel="noopener noreferrer"&gt;OAuth Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can learn more about OAuth 2.0 on &lt;a href="https://oauth.net/2/grant-types/implicit/" rel="noopener noreferrer"&gt;OAuth.net&lt;/a&gt;, or check out any of these resources to get started building!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2017/03/21/spring-boot-oauth" rel="noopener noreferrer"&gt;Get Started with Spring Boot, OAuth 2.0, and Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/03/23/token-authentication-aspnetcore-complete-guide" rel="noopener noreferrer"&gt;Token Authentication in ASP.NET Core 2.0 - A Complete Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2017/10/27/secure-spa-spring-boot-oauth" rel="noopener noreferrer"&gt;Secure your SPA with Spring Boot and OAuth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or hit up &lt;a href="https://developer.okta.com/docs/api/resources/oidc" rel="noopener noreferrer"&gt;Okta’s OIDC/OAuth 2.0 API&lt;/a&gt; for specific information on how we support OAuth. And as always, follow us on Twitter &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;@oktadev&lt;/a&gt; for more great content.&lt;/p&gt;

</description>
      <category>security</category>
      <category>oauth</category>
    </item>
    <item>
      <title>WebAuthn: A Developer's Guide to What's on the Horizon</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Tue, 17 Apr 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/webauthn-a-developers-guide-to-whats-on-the-horizon-2a5e</link>
      <guid>https://forem.com/oktadev/webauthn-a-developers-guide-to-whats-on-the-horizon-2a5e</guid>
      <description>&lt;p&gt;There’s been a lot of news lately about the new W3C Web Authentication API, also known as WebAuthn. Want to know what it’s all about? Let’s take a closer look.&lt;/p&gt;

&lt;p&gt;The Web Authentication API allows browsers to make use of hardware authenticators such as the Yubikey or a mobile phone’s biometrics, like a thumbprint reader or facial recognition. WebAuthn can be used with these technologies to enable two-factor authentication to websites, or even as the primary authentication mechanism.&lt;/p&gt;

&lt;p&gt;Much of the motivation behind the development of the spec is to reduce reliance on passwords or other authentication methods that are easily phished. The effort began under the FIDO Alliance, and was adopted by the W3C to create the &lt;a href="https://www.w3.org/TR/webauthn/"&gt;WebAuthn&lt;/a&gt; spec as the major browser vendors got on board.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does WebAuthn Work?
&lt;/h2&gt;

&lt;p&gt;Under the hood, the WebAuthn spec uses &lt;a href="https://blog.vrypan.net/2013/08/28/public-key-cryptography-for-non-geeks/"&gt;public key cryptography&lt;/a&gt; to provide a way for browsers to sign a challenge using a private key stored by the operating system or on a physical hardware token. The private key never leaves the device, and is never made available to the browser. For hardware tokens like the &lt;a href="https://www.yubico.com/"&gt;Yubikey&lt;/a&gt;, the private key isn’t even accessible to the underlying operating system!&lt;/p&gt;

&lt;p&gt;If you already have existing users with an existing authentication mechanism, letting users enroll a WebAuthn credential will work something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have your users log in using their existing credentials&lt;/li&gt;
&lt;li&gt;Create a new WebAuthn credential and associate it with the user account&lt;/li&gt;
&lt;li&gt;When the user returns, prompt them for their WebAuthn credential, and once verified, you can sign them in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A unique property of the WebAuthn API is that it can’t be used to identify users between different websites. The credentials generated are tied to the domain of the website that generated them. This provides an additional layer of privacy to users, since websites can’t use the WebAuthn credential to identify users across domains.&lt;/p&gt;

&lt;h3&gt;
  
  
  The WebAuthn JavaScript API
&lt;/h3&gt;

&lt;p&gt;The WebAuthn spec defines two new JavaScript APIs available to web applications: &lt;code&gt;navigator.credentials.create&lt;/code&gt; and &lt;code&gt;navigator.credentials.get&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You’ll use the &lt;code&gt;navigator.credentials.create&lt;/code&gt; function to enroll a new authenticator and store the resulting identifier at your server. To set up a new authenticator, you’ll first need to generate 32 random bytes on the server, and provide that to your JavaScript function. These 32 random bytes are part of the data that the authenticator will sign, so it’s important that this be generated by your server so your server knows that the resulting signed challenge was one that it initiated.&lt;/p&gt;

&lt;p&gt;When you want to ask the user to log back in with an existing credential, you can use the &lt;code&gt;navigator.credentials.get&lt;/code&gt; function to request that the user prove the possession of an existing enrolled device. If they’ve registered multiple devices, you can pass multiple identifiers to the function and the matching one will be returned.&lt;/p&gt;

&lt;p&gt;When the site runs the &lt;code&gt;navigator.credentials.create&lt;/code&gt; function, all available USB keys or other authentication mechanisms will wait for the user to interact with them. In the case of Yubikeys, you’ll see the blinking light on all of them that are currently plugged in. If you specify an existing identifier to the &lt;code&gt;navigator.credentials.get&lt;/code&gt; function, then only that one key will blink.&lt;/p&gt;

&lt;p&gt;See Mozilla’s &lt;a href="https://hacks.mozilla.org/2018/01/using-hardware-token-based-2fa-with-the-webauthn-api/"&gt;Using Hardware Token-based 2FA with the WebAuthn API&lt;/a&gt; guide for more details on the JavaScript code necessary to make this work.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Can I Use WebAuthn?
&lt;/h2&gt;

&lt;p&gt;As of April 2018, the WebAuthn API is available in Firefox Nightly, and can be turned on in Chrome by enabling a setting in &lt;code&gt;chrome://flags&lt;/code&gt;. Apple has not yet commented on whether or when WebAuthn will be available in Safari. They were involved with the development of the spec, though, so they will likely be shipping it soon.&lt;/p&gt;

&lt;p&gt;The spec itself is currently a W3C “Candidate Recommendation”, which is the second to last step before it’s finalized as a “Recommendation.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About WebAuthn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hacks.mozilla.org/2018/01/using-hardware-token-based-2fa-with-the-webauthn-api/"&gt;Using Hardware Token-based 2FA with the WebAuthn API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/microsoft-edge/dev-guide/device/web-authentication"&gt;Web authentication and Windows Hello&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fidoalliance.org/fido2/"&gt;FIDO2 Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Learn more about &lt;a href="https://www.okta.com/blog/2018/04/its-a-new-world-with-webauthn-passwordless-authentication-goes-primetime/"&gt;Okta’s plans to support WebAuthn&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What is the OAuth 2.0 Authorization Code Grant Type?</title>
      <dc:creator>Aaron Parecki</dc:creator>
      <pubDate>Tue, 10 Apr 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/what-is-the-oauth-20-authorization-code-grant-type-368m</link>
      <guid>https://forem.com/oktadev/what-is-the-oauth-20-authorization-code-grant-type-368m</guid>
      <description>&lt;p&gt;The Authorization Code Grant Type is probably the most common of the OAuth 2.0 grant types that you’ll encounter. It is used by both web apps and native apps to get an access token after a user authorizes an app.&lt;/p&gt;

&lt;p&gt;This post is the first part of a series where we explore frequently used OAuth 2.0 grant types. If you want to back up a bit and learn more about OAuth 2.0 before we dive in, check out &lt;a href="https://dev.to/blog/2017/06/21/what-the-heck-is-oauth"&gt;What the Heck is OAuth?&lt;/a&gt;, also on the Okta developer blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an OAuth 2.0 Grant Type?
&lt;/h2&gt;

&lt;p&gt;In OAuth 2.0, the term “grant type” refers to the way an application gets an access token. OAuth 2.0 defines several grant types, including the authorization code flow. OAuth 2.0 extensions can also define new grant types.&lt;/p&gt;

&lt;p&gt;Each grant type is optimized for a particular use case, whether that’s a web app, a native app, a device without the ability to launch a web browser, or server-to-server applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Authorization Code Flow
&lt;/h2&gt;

&lt;p&gt;The Authorization Code grant type is used by web and mobile apps. It differs from most of the other grant types by first requiring the app launch a browser to begin the flow. At a high level, the flow has the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application opens a browser to send the user to the OAuth server&lt;/li&gt;
&lt;li&gt;The user sees the authorization prompt and approves the app’s request&lt;/li&gt;
&lt;li&gt;The user is redirected back to the application with an authorization code in the query string&lt;/li&gt;
&lt;li&gt;The application exchanges the authorization code for an access token&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Get the User’s Permission
&lt;/h3&gt;

&lt;p&gt;OAuth is all about enabling users to grant limited access to applications. The application first needs to decide which permissions it is requesting, then send the user to a browser to get their permission. To begin the authorization flow, the application constructs a URL like the following and opens a browser to that URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://authorization-server.com/auth
 ?response_type=code
 &amp;amp;client_id=29352915982374239857
 &amp;amp;redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
 &amp;amp;scope=create+delete
 &amp;amp;state=xcoiv98y2kd22vusuye3kch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s each query parameter explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;response_type=code&lt;/code&gt; - This tells the authorization server that the application is initiating the authorization code flow.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_id&lt;/code&gt; - The public identifier for the application, obtained when the developer first registered the application.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect_uri&lt;/code&gt; - Tells the authorization server where to send the user back to after they approve the request.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scope&lt;/code&gt; - One or more space-separated strings indicating which permissions the application is requesting. The specific OAuth API you’re using will define the scopes that it supports.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;state&lt;/code&gt; - The application generates a random string and includes it in the request. It should then check that the same value is returned after the user authorizes the app. This is used to prevent &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29"&gt;CSRF attacks&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the user visits this URL, the authorization server will present them with a prompt asking if they would like to authorize this application’s request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SV-j-3W4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/oauth-authorization-code-grant-type/oauth-prompt-6489c6516fda5e0deea637d96f8398683fea6ade6054ee779e306e0b8ac5dcb8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SV-j-3W4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/oauth-authorization-code-grant-type/oauth-prompt-6489c6516fda5e0deea637d96f8398683fea6ade6054ee779e306e0b8ac5dcb8.png" alt="OAuth Prompt" width="576" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Redirect Back to the Application
&lt;/h3&gt;

&lt;p&gt;If the user approves the request, the authorization server will redirect the browser back to the &lt;code&gt;redirect_uri&lt;/code&gt; specified by the application, adding a &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;state&lt;/code&gt; to the query string.&lt;/p&gt;

&lt;p&gt;For example, the user will be redirected back to a URL such as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://example-app.com/redirect
 ?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
 &amp;amp;state=xcoiv98y2kd22vusuye3kch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;state&lt;/code&gt; value will be the same value that the application initially set in the request. The application is expected to check that the state in the redirect matches the state it originally set. This protects against CSRF and other related attacks.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;code&lt;/code&gt; is the authorization code generated by the authorization server. This code is relatively short-lived, typically lasting between 1 to 10 minutes depending on the OAuth service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exchange the Authorization Code for an Access Token
&lt;/h3&gt;

&lt;p&gt;We’re about ready to wrap up the flow. Now that the application has the authorization code, it can use that to get an access token.&lt;/p&gt;

&lt;p&gt;The application makes a POST request to the service’s token endpoint with the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;grant_type=authorization_code&lt;/code&gt; - This tells the token endpoint that the application is using the Authorization Code grant type.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;code&lt;/code&gt; - The application includes the authorization code it was given in the redirect.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirect_uri&lt;/code&gt; - The same redirect URI that was used when requesting the code. Some APIs don’t require this parameter, so you’ll need to double check the documentation of the particular API you’re accessing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_id&lt;/code&gt; - The application’s client ID.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client_secret&lt;/code&gt; - The application’s client secret. This ensures that the request to get the access token is made only from the application, and not from a potential attacker that may have intercepted the authorization code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The token endpoint will verify all the parameters in the request, ensuring the code hasn’t expired and that the client ID and secret match. If everything checks out, it will generate an access token and return it in the response!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
  "scope":"create delete"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Authorization Code flow is complete! The application now has an access token it can use when making API requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use the Authorization Code Flow
&lt;/h2&gt;

&lt;p&gt;The Authorization Code flow is best used in web and mobile apps. Since the Authorization Code grant has the extra step of exchanging the authorization code for the access token, it provides an additional layer of security not present in the Implicit grant type.&lt;/p&gt;

&lt;p&gt;If you’re using the Authorization Code flow in a mobile app, or any other type of application that can’t store a client secret, then you should also use the &lt;a href="https://www.oauth.com/oauth2-servers/pkce/"&gt;PKCE extension&lt;/a&gt;, which provides protections against other attacks where the authorization code may be intercepted.&lt;/p&gt;

&lt;p&gt;The code exchange step ensures that an attacker isn’t able to intercept the access token, since the access token is always sent via a secure backchannel between the application and the OAuth server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About OAuth and Okta
&lt;/h2&gt;

&lt;p&gt;You can learn more about OAuth 2.0 on &lt;a href="https://www.oauth.com/"&gt;OAuth.com&lt;/a&gt;, or check out any of these resources to get started building!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2017/03/21/spring-boot-oauth"&gt;Get Started with Spring Boot, OAuth 2.0, and Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2018/03/23/token-authentication-aspnetcore-complete-guide"&gt;Token Authentication in ASP.NET Core 2.0 - A Complete Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/blog/2017/10/27/secure-spa-spring-boot-oauth"&gt;Secure your SPA with Spring Boot and OAuth&lt;/a&gt;Or hit up &lt;a href="https://dev.to/docs/api/resources/oidc"&gt;Okta’s OIDC/OAuth 2.0 API&lt;/a&gt; for specific information on how we support OAuth. And as always, follow us on Twitter &lt;a href="https://twitter.com/oktadev"&gt;@oktadev&lt;/a&gt; for more great content.&lt;/li&gt;
&lt;/ul&gt;

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