<?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>DEV Community: Cole Hafner</title>
    <description>The latest articles on DEV Community by Cole Hafner (@colehafner).</description>
    <link>https://dev.to/colehafner</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%2F121839%2F37955911-31d0-4bad-ae49-1c76e3b7381f.png</url>
      <title>DEV Community: Cole Hafner</title>
      <link>https://dev.to/colehafner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/colehafner"/>
    <language>en</language>
    <item>
      <title>OAuth2 From Scratch</title>
      <dc:creator>Cole Hafner</dc:creator>
      <pubDate>Tue, 11 Feb 2020 08:08:52 +0000</pubDate>
      <link>https://dev.to/colehafner/oauth2-from-scratch-11ij</link>
      <guid>https://dev.to/colehafner/oauth2-from-scratch-11ij</guid>
      <description>&lt;p&gt;You see it everywhere: "login with &amp;lt; Google|Twitter|GitHub|Facebook|etc &amp;gt;". Personally I like it, A LOT. It's fast, easy, and saves me time. Who needs more passwords to remember? Heck, I used it to login to write this post. &lt;/p&gt;

&lt;p&gt;Now it's time to find out how it works. Come with me, as we journey into the magical world of OAuth 2...&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk9gr1ax1xfjxkdgag8rj.jpeg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk9gr1ax1xfjxkdgag8rj.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  TLDR
&lt;/h3&gt;

&lt;p&gt;OAuth 2 is easy to implement. There are just 2 steps: request a code and use that code to get a token. That's it.  If you prefer reading this post in another language, &lt;a href="https://github.com/coleHafner/oauth-test/tree/parcel" rel="noopener noreferrer"&gt;I translated it to typescript&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up the client
&lt;/h3&gt;

&lt;p&gt;I chose Google, but, since OAuth is a standard, it should be fairly similar for any provider. Here's how to set up an OAuth client with Google:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new project &lt;a href="https://console.developers.google.com/apis/dashboard" rel="noopener noreferrer"&gt;on Google dashboard&lt;/a&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb79epetfel0uraq0jxky.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Enable APIs for that project. You can enable ANY service Google has: Drive, Gmail, Sheets, Docs, Voice-to-text, etc. The basic one you'll need is the Google People API, which provides information about user profiles
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsp16px5qcn65t0v98vxv.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Create an OAuth client. This will be the client id/secret you need for requesting the oAuth token. First click 'Create Credentials' and then OAuth Client ID. It will prompt you to create a consent screen. Follow the prompts and then fill out the form like this. Make sure to set up the authorized domains and redirect domains. I'm using &lt;code&gt;https://localhost&lt;/code&gt;, but you can use whatever you like, as long as it's HTTPS. It's easy to run HTTPS locally with &lt;a href="https://www.npmjs.com/package/https-localhost" rel="noopener noreferrer"&gt;this node package&lt;/a&gt;.
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Faz99q6agr6nflmgaqgs9.png" alt="Alt Text"&gt;
&lt;/li&gt;
&lt;li&gt;Copy the client id and secret for later use. &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Get a Token
&lt;/h3&gt;

&lt;p&gt;Now here's the fun part. It takes just 2 steps to get an OAuth token from Google:&lt;/p&gt;

&lt;h4&gt;
  
  
  Request an authorization code
&lt;/h4&gt;

&lt;p&gt;The code is not THE token, it's called the authorization code and it's used to get the token later.&lt;/p&gt;

&lt;p&gt;"That's dumb. Why not just send the token?" Good question. It used to be that way. It is called the &lt;a href="https://oauth.net/2/grant-types/implicit/" rel="noopener noreferrer"&gt;Implicit Grant Type&lt;/a&gt;. It's a &lt;em&gt;bad idea&lt;/em&gt; and generally not recommended any more (in some cases outright banned). &lt;/p&gt;

&lt;p&gt;We'll be using the &lt;a href="https://oauth.net/2/grant-types/authorization-code/" rel="noopener noreferrer"&gt;Authorization Code Grant Type&lt;/a&gt;. It takes one more step, but is more secure.&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;// GET request with the following params&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;code_challenge_method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;S256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// tells google what info you want&lt;/span&gt;
   &lt;span class="nx"&gt;access_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;response_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// clientID from step 1&lt;/span&gt;
   &lt;span class="nx"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// page that handles token request&lt;/span&gt;
   &lt;span class="nx"&gt;code_challenge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;challengeToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// hashed/encoded PKCE challenge&lt;/span&gt;
   &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stateString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// random guid that will be passed back to you&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;// example&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://accounts.google.com/o/oauth2/v2/auth?code_challenge_method=S256&amp;amp;scope=email%20profile&amp;amp;access_type=offline&amp;amp;response_type=code&amp;amp;client_id=&amp;lt;client id&amp;gt;&amp;amp;redirect_uri=https://localhost/auth&amp;amp;code_challenge=o259Sjip6Cevgfe8RUw59jVO5z1mSzji_OuzIZFDTug&amp;amp;state=434595.10145617445&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nx"&gt;Login&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;Google&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The aforementioned &lt;code&gt;code_challenge&lt;/code&gt; parameter is from a method called &lt;a href="https://oauth.net/2/pkce/" rel="noopener noreferrer"&gt;PKCE&lt;/a&gt;. It stands for Proof Key for Code Exchange and is a security method to help make OAuth more secure. At its core, it's an hashed string that you send to the provider so it can verify your identity in the second step by sending the original string from which it was hashed. There's a real helpful &lt;a href="https://www.npmjs.com/package/pkce-challenge" rel="noopener noreferrer"&gt;node package&lt;/a&gt; that helps you generate PKCE challenges. &lt;/p&gt;

&lt;h4&gt;
  
  
  Request the OAuth Token
&lt;/h4&gt;

&lt;p&gt;If all goes right on the first request, the provider will ask the user to login, generate the authorization code, and redirect to the uri specified in the &lt;code&gt;redirect_uri&lt;/code&gt; param. It will include 2 important URL params: &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;state&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Code is the authorization code needed to request the OAuth token.&lt;/p&gt;

&lt;p&gt;State is the initial &lt;code&gt;state&lt;/code&gt; param you sent in the last step. It's a simple mechanism to ensure the client can verify the identity of the server. If the state doesn't match, or isn't included, you can know not to trust that request.&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;// POST request with the following params&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;authCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// authorization code from the provider&lt;/span&gt;
   &lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// id of the OAuth client&lt;/span&gt;
   &lt;span class="nx"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// secret of the OAuth client&lt;/span&gt;
   &lt;span class="nx"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// same from last request ¯\_(ツ)_/¯&lt;/span&gt;
   &lt;span class="nx"&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="s1"&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="nx"&gt;code_verifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;codeVerifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// raw PKCE token&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// returns the following payload&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; 
   &lt;span class="na"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;access&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// this can be used to query APIs&lt;/span&gt;
   &lt;span class="na"&gt;refresh_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;refresh&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// can be used to get a new token&lt;/span&gt;
   &lt;span class="na"&gt;expires_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;expiration&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// usually set to an hour&lt;/span&gt;
   &lt;span class="na"&gt;id_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// haven't really found a use for this&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Use the Token!
&lt;/h4&gt;

&lt;p&gt;You can then use the token to get data from Google on behalf of the user.&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="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.googleapis.com/oauth2/v2/userinfo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="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/json; 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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Google has a cool &lt;a href="https://developers.google.com/oauthplayground" rel="noopener noreferrer"&gt;OAuth playground&lt;/a&gt; where you can try out all kinds of APIs. &lt;/p&gt;

&lt;p&gt;That's it! You're done! &lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;Here's a link to some of the resources I used to learn about this:&lt;/p&gt;

&lt;p&gt;PKCE explanation: &lt;a href="https://oauth.net/2/pkce/" rel="noopener noreferrer"&gt;https://oauth.net/2/pkce/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PKCE node package: &lt;a href="https://www.npmjs.com/package/pkce-challenge" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/pkce-challenge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google OAuth Playground: &lt;a href="https://developers.google.com/oauthplayground" rel="noopener noreferrer"&gt;https://developers.google.com/oauthplayground&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;OAuth2 Overview: &lt;a href="https://aaronparecki.com/oauth-2-simplified/#web-server-apps" rel="noopener noreferrer"&gt;https://aaronparecki.com/oauth-2-simplified/#web-server-apps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google OAuth Walkthrough: &lt;a href="https://developers.google.com/identity/protocols/OAuth2InstalledApp#obtainingaccesstokens" rel="noopener noreferrer"&gt;https://developers.google.com/identity/protocols/OAuth2InstalledApp#obtainingaccesstokens&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sample GitHub repo: &lt;a href="https://github.com/coleHafner/oauth-test/tree/parcel" rel="noopener noreferrer"&gt;https://github.com/coleHafner/oauth-test/tree/parcel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>oauth2</category>
      <category>pkce</category>
      <category>react</category>
    </item>
  </channel>
</rss>
