<?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: Randall Degges</title>
    <description>The latest articles on DEV Community by Randall Degges (@rdegges).</description>
    <link>https://dev.to/rdegges</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%2F54664%2F110f8a94-228e-4c98-882f-5cab148205ef.png</url>
      <title>DEV Community: Randall Degges</title>
      <link>https://dev.to/rdegges</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rdegges"/>
    <language>en</language>
    <item>
      <title>Build and Understand a Simple Node.js Website with User Authentication</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Fri, 17 Aug 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/build-and-understand-a-simple-nodejs-website-with-user-authentication-4ml9</link>
      <guid>https://dev.to/oktadev/build-and-understand-a-simple-nodejs-website-with-user-authentication-4ml9</guid>
      <description>&lt;p&gt;Building websites with user authentication and management (login, registration, password reset, etc.), can be a huge pain. As a developer there are a million little things you need to worry about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storing the users in your database&lt;/li&gt;
&lt;li&gt;Making sure you have the right user attributes defined&lt;/li&gt;
&lt;li&gt;Forcing users to be logged in to view a page&lt;/li&gt;
&lt;li&gt;Building registration and login forms&lt;/li&gt;
&lt;li&gt;Creating password reset workflows that email users a link&lt;/li&gt;
&lt;li&gt;Verifying new users when they sign up via email&lt;/li&gt;
&lt;li&gt;Etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list goes on and on.&lt;/p&gt;

&lt;p&gt;Today I’m not only going to show you how to quickly build a Node.js website that supports all those things above, I’m going to teach you exactly what’s going on behind the scenes so you fully &lt;em&gt;understand&lt;/em&gt; how web authentication works.&lt;/p&gt;

&lt;p&gt;If you’ve ever been curious about how web authentication and user security works, you will enjoy this. =)&lt;/p&gt;

&lt;h2&gt;
  
  
  What We’re Building
&lt;/h2&gt;

&lt;p&gt;As I mentioned above, today we’ll be building a simple Node.js site that supports a few key user flows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User registration&lt;/li&gt;
&lt;li&gt;User login&lt;/li&gt;
&lt;li&gt;Password reset&lt;/li&gt;
&lt;li&gt;Email verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The end product of this article looks like this:&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%2Fbuild-understand-auth-node%2Fusing-the-site-ad78534a9856b7ad496c7e2c42b4bd8fad0daedee34a410da9a872d5c49b90d1.gif" 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%2Fbuild-understand-auth-node%2Fusing-the-site-ad78534a9856b7ad496c7e2c42b4bd8fad0daedee34a410da9a872d5c49b90d1.gif" alt="using the site"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to see a preview of this project live, you can do so here: &lt;a href="https://okta-express-login-portal.herokuapp.com/" rel="noopener noreferrer"&gt;https://okta-express-login-portal.herokuapp.com/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The site will be built using a few different tools (you don’t need to know them already):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express.js&lt;/a&gt;, the most popular web framework in the Node.js ecosystem.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/expressjs/session" rel="noopener noreferrer"&gt;express-session&lt;/a&gt;, a popular session management library. This is what will allow us to create and store cookies that remember who a user is.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pugjs.org/api/getting-started.html" rel="noopener noreferrer"&gt;Pug&lt;/a&gt;, a popular templating language that makes writing HTML a bit simpler.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/oidc-middleware" rel="noopener noreferrer"&gt;oidc-middleware&lt;/a&gt;, a popular developer library that makes handling authentication using the &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt; protocol simple&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install the Tools
&lt;/h2&gt;

&lt;p&gt;The first thing you need to do is install all the open source tools we’ll be using to build this Node.js site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt; : If you don’t already have Node.js setup and working on your computer, you can go checkout &lt;a href="https://nodejs.org/en/download/package-manager/" rel="noopener noreferrer"&gt;this link&lt;/a&gt; which shows you the best way to get it working regardless of what operating system you’re using.&lt;/p&gt;

&lt;p&gt;Next, install the &lt;a href="https://github.com/expressjs/generator" rel="noopener noreferrer"&gt;express-generator&lt;/a&gt; tool, which is the officially supported bootstrapping tool for quickly getting started with Express.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express-generator@4.16.0

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

&lt;/div&gt;



&lt;p&gt;Once that’s done, you’ll want to scaffold your new Express.js site using express-generator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;express --view pug login-portal
cd login-portal
npm install

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

&lt;/div&gt;



&lt;p&gt;You now have a simple Express.js website that you can run and test out. Start up your new web server by running &lt;code&gt;npm start&lt;/code&gt; then go visit &lt;code&gt;http://localhost:3000&lt;/code&gt; in your browser to make sure everything is working OK. If all is well, you should see a page like the one below.&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%2Fbuild-understand-auth-node%2Fexpress-starter-page-74a7d3ac4c7b71de0bf430dd737a2a298a8b65c7a9bc569212fde39a3a59bb92.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%2Fbuild-understand-auth-node%2Fexpress-starter-page-74a7d3ac4c7b71de0bf430dd737a2a298a8b65c7a9bc569212fde39a3a59bb92.png" alt="express starter page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, install some additional packages. We’ll use these packages through the rest of the tutorial. Getting them installed and out of the way upfront will make it simpler later on.&lt;/p&gt;

&lt;p&gt;To install all the extra dependencies, run the following commands in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express-session@1.15.6
npm install @okta/oidc-middleware@0.1.3
npm install @okta/okta-sdk-nodejs@1.1.0

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

&lt;/div&gt;



&lt;p&gt;Now, on with the show!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Your Authorization Server
&lt;/h2&gt;

&lt;p&gt;Historically, implementing web authentication has been a bit of a mess. Everyone used to implement authentication patterns in different, arbitrary ways. Over the last few years, however, the game has changed quite a bit with the introduction and growing popularity of the OpenID Connect protocol. If you want to read up on OpenID Connect, I recommend &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;this series&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of the core tenants of OpenID Connect is the &lt;strong&gt;authorization server&lt;/strong&gt;. An authorization server is a one-stop shop that handles all of the user login flows for your applications. The idea is that your application redirects to the authorization server to process user logins and the authorization server then redirects the user back to your website once the user has been authenticated.&lt;/p&gt;

&lt;p&gt;Authorization servers make handling user management a significantly simpler, less risky task — so that’s what we’ll be doing today: using an authorization server provider (&lt;a href="https://developer.okta.com/" rel="noopener noreferrer"&gt;Okta&lt;/a&gt;) to make the process simple and secure.&lt;/p&gt;

&lt;p&gt;Okta is free to use and allows you to create and manage users, authorization servers, and lots of other tasks that make handling web authentication simple.&lt;/p&gt;

&lt;p&gt;To get started with the authorization server setup, you first need to go create a free Okta developer account: &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;https://developer.okta.com/signup/&lt;/a&gt;. Once you’ve created your account and logged in, follow the steps below configure Okta and then you’ll be ready to write some 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%2Fbuild-understand-auth-node%2Fokta-signup-ee14e7516bdc7df3e6e950a2c385706754c5300d842a1374785fd9e43cab2a6b.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%2Fbuild-understand-auth-node%2Fokta-signup-ee14e7516bdc7df3e6e950a2c385706754c5300d842a1374785fd9e43cab2a6b.png" alt="Okta signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Store Your Org URL
&lt;/h3&gt;

&lt;p&gt;The first thing you need to do is copy down the &lt;strong&gt;Org URL&lt;/strong&gt; from the top-right portion of your Okta dashboard page. This URL will be used to route to your authorization server, communicate with it, and much more. You’ll need this value later, so don’t forget it.&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%2Fbuild-understand-auth-node%2Fokta-org-url-b26a98af3fa71a8f88519b5154d16d10fae846ff3df95d09995fcd61fa2c6175.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%2Fbuild-understand-auth-node%2Fokta-org-url-b26a98af3fa71a8f88519b5154d16d10fae846ff3df95d09995fcd61fa2c6175.png" alt="Okta org url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create an OpenID Connect Application
&lt;/h3&gt;

&lt;p&gt;Okta allows you to store and manage users for multiple applications you might be creating. This means that before we can go any further, you need to create a new OpenID Connect application for this project.&lt;/p&gt;

&lt;p&gt;Applications in OpenID Connect have a username and password (referred to as a client ID and client secret) that allow your authorization server to recognize which application is talking to it at any given time.&lt;/p&gt;

&lt;p&gt;To create a new application browse to the &lt;strong&gt;Applications&lt;/strong&gt; tab 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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-understand-auth-node%2Fokta-app-dashboard-5d3d0ee99d0d6888f30bffc5fa3d58ddaafe907dfd2ec315589435b2fc7bb23b.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%2Fbuild-understand-auth-node%2Fokta-app-dashboard-5d3d0ee99d0d6888f30bffc5fa3d58ddaafe907dfd2ec315589435b2fc7bb23b.png" alt="Okta add application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click the &lt;strong&gt;Web&lt;/strong&gt; platform option (since this project is a web app).&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%2Fbuild-understand-auth-node%2Fokta-create-app-platform-681dcd71ac7de879a92e80d243020f9c9be6edc17e6ae0b0adb40a70936eac24.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%2Fbuild-understand-auth-node%2Fokta-create-app-platform-681dcd71ac7de879a92e80d243020f9c9be6edc17e6ae0b0adb40a70936eac24.png" alt="Okta create app web"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the settings page, enter the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; : login-portal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login redirect URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:3000/users/callback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can leave all the other values unchanged.&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%2Fbuild-understand-auth-node%2Fokta-create-app-settings-e232b231bc66f56f47e4ed7e784cde968a64d982f3a065c82d0ba62d929b2ac0.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%2Fbuild-understand-auth-node%2Fokta-create-app-settings-e232b231bc66f56f47e4ed7e784cde968a64d982f3a065c82d0ba62d929b2ac0.png" alt="Okta create app settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that your application has been created, copy down the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client secret&lt;/strong&gt; values on the following page, you’ll need them later when we start writing 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%2Fbuild-understand-auth-node%2Fokta-app-credentials-2f5b916ff40dc7425e731c801f9b087342846ed828a7979ab79127059d67d6b3.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%2Fbuild-understand-auth-node%2Fokta-app-credentials-2f5b916ff40dc7425e731c801f9b087342846ed828a7979ab79127059d67d6b3.png" alt="Okta signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create an Authentication Token
&lt;/h3&gt;

&lt;p&gt;In order to access the Okta APIs and be able to manage your user accounts with a great deal of granularity, you’ll also need to create an Okta authentication token. This is an API key that will be used later on communicate with the Okta APIs and allows you to do things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create, update, and delete users&lt;/li&gt;
&lt;li&gt;Create, update, and delete groups&lt;/li&gt;
&lt;li&gt;Manage application settings&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create an authentication token click the &lt;strong&gt;API&lt;/strong&gt; tab at the top of the page followed by the &lt;strong&gt;Create Token&lt;/strong&gt; button. Give your token a name, preferably the same name as your application, then click &lt;strong&gt;Create Token&lt;/strong&gt;. Once your token has been created, copy down the token value as you will need it 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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-understand-auth-node%2Fokta-create-token-008a4364f7541ac93b9baf5d3b381ba889bd7188fd6101b19901f0cdf9821a6c.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%2Fbuild-understand-auth-node%2Fokta-create-token-008a4364f7541ac93b9baf5d3b381ba889bd7188fd6101b19901f0cdf9821a6c.png" alt="Okta create token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Enable User Registration
&lt;/h3&gt;

&lt;p&gt;The last piece of setup you need to complete is to enable user registration functionality for the authorization server. Normally, authorization servers only support login, logout, and stuff like that. But Okta’s authorization server also supports self-service registration, so that users can create accounts, log into them, reset passwords, and basically do everything without you writing any code for it.&lt;/p&gt;

&lt;p&gt;In your Okta dashboard, you’ll notice a small button labeled &lt;strong&gt;&amp;lt; &amp;gt; Developer Console&lt;/strong&gt; at the top-left of your page. Hover over that button and select the &lt;strong&gt;Classic UI&lt;/strong&gt; menu option that appears.&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%2Fbuild-understand-auth-node%2Fokta-switch-to-classic-ui-249d1b924c3db38af5d62bf17be65a32579117d9d23c8c28cb7e365eba7d8f85.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%2Fbuild-understand-auth-node%2Fokta-switch-to-classic-ui-249d1b924c3db38af5d62bf17be65a32579117d9d23c8c28cb7e365eba7d8f85.png" alt="Okta switch to classic ui"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, hover over the &lt;strong&gt;Directory&lt;/strong&gt; tab at the top of the page then select the &lt;strong&gt;Self-Service Registration&lt;/strong&gt; menu item. On this page click the &lt;strong&gt;Enable Registration&lt;/strong&gt; button.&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%2Fbuild-understand-auth-node%2Fokta-enable-registration-2cfef05884c196fa53bc7c55728c77437713fffa5d549e1874e18c2593825b1f.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%2Fbuild-understand-auth-node%2Fokta-enable-registration-2cfef05884c196fa53bc7c55728c77437713fffa5d549e1874e18c2593825b1f.png" alt="Okta enable registration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the configuration page, leave all the settings as their default values, except for the &lt;strong&gt;Default redirect&lt;/strong&gt; option. For this option, click the &lt;strong&gt;Custom URL&lt;/strong&gt; radiobox and enter &lt;code&gt;http://localhost:3000/dashboard&lt;/code&gt; as the value.&lt;/p&gt;

&lt;p&gt;This setting essentially tells the authorization server where to redirect users after they’ve successfully created a new account on your site.&lt;/p&gt;

&lt;p&gt;Once you’ve clicked &lt;strong&gt;Save&lt;/strong&gt; , the last thing you need to is switch back to the developer console.&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%2Fbuild-understand-auth-node%2Fokta-registration-settings-1c56ddf046d5ddf4c58559a76adf32dd03624a076c2ba13a5d92639b9fe1280e.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%2Fbuild-understand-auth-node%2Fokta-registration-settings-1c56ddf046d5ddf4c58559a76adf32dd03624a076c2ba13a5d92639b9fe1280e.png" alt="Okta registration settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hover over the &lt;strong&gt;Classic UI&lt;/strong&gt; button at the top right of the page and select the &lt;strong&gt;&amp;lt; &amp;gt; Developer Console&lt;/strong&gt; menu item from the dropdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Session Management
&lt;/h2&gt;

&lt;p&gt;Now that all the setup work is done, let’s write some code!&lt;/p&gt;

&lt;p&gt;The first thing we’ll add to this basic Express.js site is support for sessions using the &lt;a href="https://github.com/expressjs/session" rel="noopener noreferrer"&gt;express-session&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;Session management is the core of any authentication system. It’s what allows a user to stay logged into your site and not have to re-enter their credentials before viewing each page. The most &lt;a href="https://www.rdegges.com/2018/please-stop-using-local-storage/" rel="noopener noreferrer"&gt;secure way&lt;/a&gt; to handle user sessions is via server-side cookies, which is why we’ll be using the express-session library: it allows us to create and manage server-side cookies.&lt;/p&gt;

&lt;p&gt;To start, open up the &lt;code&gt;./app.js&lt;/code&gt; file in your favorite editor (I prefer &lt;a href="https://neovim.io/" rel="noopener noreferrer"&gt;neovim&lt;/a&gt;), and import the session library at the top of the file alongside the other import statements. The &lt;code&gt;app.js&lt;/code&gt; file is the heart of your Express.js site. It initializes the Express.js web server, contains the site settings, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var session = require("express-session");

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

&lt;/div&gt;



&lt;p&gt;Next, you need to remove the &lt;code&gt;cookie-parser&lt;/code&gt; library that express-generator included by default, since we won’t be using it. In the &lt;code&gt;./app.js&lt;/code&gt; file delete the following two lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var cookieParser = require('cookie-parser');

// and...

app.use(cookieParser());

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

&lt;/div&gt;



&lt;p&gt;Now all you need to do is plug the express-session library into the &lt;code&gt;./app.js&lt;/code&gt; file along with the other middlewares.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
  secret: 'LONG_RANDOM_STRING_HERE',
  resave: true,
  saveUninitialized: false
}));

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

&lt;/div&gt;



&lt;p&gt;Make sure to replace &lt;code&gt;LONG_RANDOM_STRING_HERE&lt;/code&gt; with an actual random string you type. This string is what will keep your user’s cookies safe from compromise. I personally like to bash my hands around on the keyboard for a second to generate something random.&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%2Fbuild-understand-auth-node%2Fprogramming-103ce847f2a5747490d5037401aa3c12f5623f61862c34be0affa9a183498ff1.gif" 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%2Fbuild-understand-auth-node%2Fprogramming-103ce847f2a5747490d5037401aa3c12f5623f61862c34be0affa9a183498ff1.gif" alt="programming"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This session library handles a lot of work behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It creates secure, cryptographically signed cookies so you can store data in a user’s browser. Cryptographic signing is a technique that allows your server to tell whether or not a user has tried to “modify” their cookies to make it look as if they’re someone they’re not.&lt;/li&gt;
&lt;li&gt;It gives you a simple API for creating and removing cookies&lt;/li&gt;
&lt;li&gt;It allows you to tweak and configure cookie settings based on what you need to do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you’ll see in a moment, this library is used by the oidc-middleware library behind the scenes to make user authentication magical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Express.js Views
&lt;/h2&gt;

&lt;p&gt;The next thing we’re going to do is create our Express.js views. Views in Express.js are nothing more than HTML templates (web pages) that we want to display to a user. But unlike normal HTML, we’ll be using the &lt;a href="https://pugjs.org/api/getting-started.html" rel="noopener noreferrer"&gt;Pug&lt;/a&gt; templating language to create our views.&lt;/p&gt;

&lt;p&gt;Pug is one of the most popular templating languages in the Node.js ecosystem because it allows you more concisely write HTML, use variables, and things like that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Layout View
&lt;/h3&gt;

&lt;p&gt;The first (and most important!) view we’re going to create is the &lt;code&gt;./views/layout.pug&lt;/code&gt; view. This is the “base” view that all our other views will extend.&lt;/p&gt;

&lt;p&gt;In this view we’ll define the basic layout of all the pages, the navbar, and stuff like that. Open up the &lt;code&gt;./views/layout.pug&lt;/code&gt; and replace whatever is in the file with 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;block variables

doctype html
html(lang="en")
  head
    meta(charset="utf-8")
    meta(name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no")
    link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous")
    link(rel="stylesheet", href="/stylesheets/style.css")
    title okta-express-login-portal: #{title}
  body
    div.top-bar.d-flex.flex-column.flex-md-row.align-items-center.p-3.px-md-4.mb-3.bg-white.border-bottom.box-shadow
      h5.my-0.mr-md-auto.font-weight-normal
        a(href="/", title="Expresso") okta-express-login-portal
      nav.my-2.my-md-0.mr-md-3
        a.p-2.text-dark(href="/", title="Home") Home

        if user == undefined
          a.p-2.text-dark(href="/users/login") Log In / Register
        else
          a.p-2.text-dark(href="/dashboard") Dashboard
          a.p-2.text-dark(href="/users/logout") Logout
    .container
      block content

    footer.
      Built with #[a(href="https://expressjs.com/") Express.js], login powered by #[a(href="https://developer.okta.com/") Okta].

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

&lt;/div&gt;



&lt;p&gt;As you can probably figure out if you’re at all familiar with HTML, pug is very similar to HTML but uses whitespace instead of closing tags (like the Python programming language).&lt;/p&gt;

&lt;p&gt;This layout view doesn’t do anything except render a simple page with a navbar at the top, a footer at the bottom, and two special constructs, &lt;code&gt;block variables&lt;/code&gt; and &lt;code&gt;block content&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;block variables&lt;/code&gt; line at the top of the file means that any of the templates that inherit from this one will be able to inject some variables into the page. You might have noticed that the &lt;code&gt;title&lt;/code&gt; tag contains a variable: &lt;code&gt;#{title}&lt;/code&gt; — this is one of the variables that a child template can overwrite later on.&lt;/p&gt;

&lt;p&gt;Did you notice the &lt;code&gt;block content&lt;/code&gt; line right above the footer? This block allows a child template to inject HTML into our layout template at just the right spot — this way our child templates don’t need to re-define a navbar, page header, etc.&lt;/p&gt;

&lt;p&gt;By using these two blocks: &lt;code&gt;variables&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt;, our child templates can build full web pages with nothing more than a title and some body content. Pretty nifty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Homepage View
&lt;/h3&gt;

&lt;p&gt;The next view we’ll create is the &lt;code&gt;./views/index.pug&lt;/code&gt; view. Open that file and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block variables
  - var title = "Home"

block content
  h2.text-center Express App

  .row
    .offset-sm-2.col-sm-8
      .jumbotron.text-center.
        Welcome to your new Express app! Please visit the
        #[a(href="https://github.com/rdegges/okta-express-login-portal", title="okkta-express-login-portal on GitHub") GitHub page] to learn more.

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

&lt;/div&gt;



&lt;p&gt;Notice the &lt;code&gt;extends layout&lt;/code&gt; line at the top. This is what tells pug that this template is a child of the &lt;code&gt;layout&lt;/code&gt; template we created earlier.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;block variables&lt;/code&gt; section we then define our &lt;code&gt;title&lt;/code&gt; variable which will be used in the layout template to output the page title, and in the &lt;code&gt;block content&lt;/code&gt; section we insert the HTML for the rest of the page.&lt;/p&gt;

&lt;p&gt;As you can hopefully see by now, template inheritance in Pug is pretty straightforward.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Dashboard View
&lt;/h3&gt;

&lt;p&gt;The next view to create is the dashboard view. This is the page users will see once they’ve logged into the site. Open up the &lt;code&gt;./views/dashboard.pug&lt;/code&gt; file and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block variables
  - var title = "Dashboard"

block content
  h2.text-center Dashboard

  .row
    .offset-sm-2.col-sm-8
      .jumbotron.text-center.
        Welcome to your dashboard page, #{user.profile.firstName}.

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

&lt;/div&gt;



&lt;p&gt;You’ll notice that in this template there’s a new variable being used: &lt;code&gt;#{user}&lt;/code&gt;. This will &lt;em&gt;eventually&lt;/em&gt; refer to the currently logged in user as you’ll see later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the Error Views
&lt;/h3&gt;

&lt;p&gt;The last two views you need to create are for handling errors.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;./views/error.pug&lt;/code&gt; view and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block content
  h1= message
  h2= error.status
  pre #{error.stack}

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

&lt;/div&gt;



&lt;p&gt;This view will be rendered when the user hits a URL that doesn’t exist (404), or when the web server has a problem (5XX).&lt;/p&gt;

&lt;p&gt;You’ll also need to create a file named &lt;code&gt;./views/unauthenticated.pug&lt;/code&gt; and insert the following code. This view will be displayed to a user if they visit a page that requires them to be 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;extends layout

block variables
  - var title = "Unauthenticated"

block content
  h2.text-center You Must Log In to View This Page
  p.text-center.
    You must be signed in to view this page. Please #[a(href="/users/login", title="Login") login or register] to view this page.

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Public Routes
&lt;/h2&gt;

&lt;p&gt;Routes in Express.js are the place where you define application logic. They dictate what code runs when a particular URL is hit by a user, and what response is sent back.&lt;/p&gt;

&lt;p&gt;To get started, let’s remove the default routes that express-generator created for you. Run the following command to remove them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm routes/*

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

&lt;/div&gt;



&lt;p&gt;Next, create a file named &lt;code&gt;./routes/public.js&lt;/code&gt; and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");

const router = express.Router();

// Home page
router.get("/", (req, res) =&amp;gt; {
  res.render("index");
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;In this module we’re creating a new &lt;a href="https://expressjs.com/en/4x/api.html#router" rel="noopener noreferrer"&gt;Express.js Router&lt;/a&gt; and telling it that if a user makes a GET request to the &lt;code&gt;/&lt;/code&gt; URL, then we’re going to run a function that renders the &lt;code&gt;index.pug&lt;/code&gt; view file we created earlier and returns it to the user.&lt;/p&gt;

&lt;p&gt;Now this won’t take effect just yet (for reasons you’ll learn about later on), but once this router is “enabled”, every time a user makes a request for the homepage of the site, eg: &lt;code&gt;http://localhost:3000&lt;/code&gt;, this code will run and the &lt;code&gt;index.pug&lt;/code&gt; view will be shown.&lt;/p&gt;

&lt;p&gt;Pretty neat, right?&lt;/p&gt;

&lt;p&gt;Next, create a file named &lt;code&gt;./routes/dashboard.js&lt;/code&gt; and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");

const router = express.Router();

// Display the dashboard page
router.get("/", (req, res) =&amp;gt; {
  res.render("dashboard");
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;This router acts similarly to the homepage router above, except it is rendering our dashboard page. While it doesn’t make sense just yet, if a user eventually visits the &lt;code&gt;/dashboard&lt;/code&gt; URL, this function will run which will render the &lt;code&gt;dashboard.pug&lt;/code&gt; defined earlier.&lt;/p&gt;

&lt;p&gt;If you were to go into this file and define another route, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;router.get("/test", (req, res) =&amp;gt; {
  res.render("test");
});

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

&lt;/div&gt;



&lt;p&gt;… You would find that a user would need to visit &lt;code&gt;/dashboard/test&lt;/code&gt; to trigger the function to run. Again: don’t worry about this not adding up just yet, we’ll get to that down below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable the Routes
&lt;/h2&gt;

&lt;p&gt;Now that you’ve created some routes for public pages, let’s &lt;em&gt;enable&lt;/em&gt; them with Express.js so we can actually see them in action!&lt;/p&gt;

&lt;p&gt;To do this, open up the &lt;code&gt;./app.js&lt;/code&gt; file and delete the following two lines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

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

&lt;/div&gt;



&lt;p&gt;Replace those two lines with the two lines of code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dashboardRouter = require("./routes/dashboard");        
const publicRouter = require("./routes/public");

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

&lt;/div&gt;



&lt;p&gt;Now we’re importing the correct route files we just defined above.&lt;/p&gt;

&lt;p&gt;Next, scroll down until you see the following two lines of code and delete them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use('/', indexRouter);
app.use('/users', usersRouter);

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

&lt;/div&gt;



&lt;p&gt;Those lines of code were loading up the old routes we just deleted. Now you need to change those lines of code to look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use('/', publicRouter);
app.use('/dashboard', dashboardRouter);

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

&lt;/div&gt;



&lt;p&gt;Is it starting to make sense now? These &lt;code&gt;app.use&lt;/code&gt; lines of code tell Express.js that if a user visits the &lt;code&gt;/&lt;/code&gt; URL, it should look into the &lt;code&gt;./routes/public.js&lt;/code&gt; file and start matching URLs there to run against. So if a user visits the homepage, eg: &lt;code&gt;/&lt;/code&gt;, Express.js will look in the &lt;code&gt;./routes/public.js&lt;/code&gt; file, find the route that serves the &lt;code&gt;/&lt;/code&gt; URL, then run the associated function.&lt;/p&gt;

&lt;p&gt;The same thing happens with the &lt;code&gt;dashboardRouter&lt;/code&gt; below. If a user visits &lt;code&gt;/dashboard&lt;/code&gt;, then Express.js will look in the &lt;code&gt;./routes/dashboard.js&lt;/code&gt; file for a function that runs when the &lt;code&gt;/&lt;/code&gt; URL is called, because &lt;code&gt;/dashboard&lt;/code&gt; + &lt;code&gt;/&lt;/code&gt; is the path the user is visiting!&lt;/p&gt;

&lt;p&gt;Routes in Express.js make it easy to compose complex sites with lots of nested URLs without a lot of work.&lt;/p&gt;

&lt;p&gt;Now that you’ve enabled your routes, go test them out. Start your web server by running 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;npm start

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

&lt;/div&gt;



&lt;p&gt;Then visit &lt;code&gt;http://localhost:3000&lt;/code&gt; in your browser. You should see the following page rendered.&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%2Fbuild-understand-auth-node%2Fapp-unstyled-6a691ad9bdb0c2ea4bacaf4cf9c11398cd1a4e79e985a0b94f32bb06de4ef8b0.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%2Fbuild-understand-auth-node%2Fapp-unstyled-6a691ad9bdb0c2ea4bacaf4cf9c11398cd1a4e79e985a0b94f32bb06de4ef8b0.png" alt="app unstyled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : This page doesn’t look just right yet because we haven’t created any CSS yet. We’ll do that last.&lt;/p&gt;

&lt;p&gt;If you now go visit the dashboard page you created, &lt;code&gt;http://localhost:3000/dashboard&lt;/code&gt;, you’ll notice you get an error. That is because that Pug view refers to the &lt;code&gt;#{user}&lt;/code&gt; variable we haven’t yet defined. We’ll get to that soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure User Authentication
&lt;/h2&gt;

&lt;p&gt;Now that our Express.js site is starting to become functional, let’s dive deeper into user authentication.&lt;/p&gt;

&lt;p&gt;The first thing you need to do is open up &lt;code&gt;./app.js&lt;/code&gt; and import the following two libraries at the top of the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var session = require('express-session');
var okta = require("@okta/okta-sdk-nodejs");
var ExpressOIDC = require("@okta/oidc-middleware").ExpressOIDC;

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

&lt;/div&gt;



&lt;p&gt;The two libraries we just added are at the bottom of the list: &lt;code&gt;@okta/okta-sdk-nodejs&lt;/code&gt; and &lt;code&gt;@okta/oidc-middleware&lt;/code&gt;. These two libraries handle all of the OpenID Connect communication and routing.&lt;/p&gt;

&lt;p&gt;The next thing we need to do is create an &lt;code&gt;oktaClient&lt;/code&gt; object as well as an &lt;code&gt;ExpressOIDC&lt;/code&gt; object. These will be used in a moment once we’ve configured them and given them the right credentials.&lt;/p&gt;

&lt;p&gt;To do this, open up your &lt;code&gt;./app.js&lt;/code&gt; file again, find the line that reads &lt;code&gt;var app = express();&lt;/code&gt;, and insert the following code immediately beneath it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var oktaClient = new okta.Client({
  orgUrl: 'https://{yourOktaDomain}',
  token: '{yourOktaToken}'
});

const oidc = new ExpressOIDC({
  issuer: "https://{yourOktaDomain}/oauth2/default",
  client_id: {yourClientId},
  client_secret: {yourClientSecret},
  redirect_uri: 'http://localhost:3000/users/callback',
  scope: "openid profile",
  routes: {
    login: {
      path: "/users/login"
    },
    callback: {
      path: "/users/callback",
      defaultRedirect: "/dashboard"
    }
  }
});

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

&lt;/div&gt;



&lt;p&gt;Now, remember those values I told you to write down way back at the beginning of this post? Now you need them! Make sure you substitute out the following variables above for the proper values: &lt;code&gt;{yourOktaDomain}&lt;/code&gt;, &lt;code&gt;{yourOktaToken}&lt;/code&gt;, &lt;code&gt;{yourClientId}&lt;/code&gt;, and &lt;code&gt;{yourClientSecret}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;oidc&lt;/code&gt; object created handles 100% of the OpenID Connect protocol support. It handles router the users to the authorization server to handle user registration, login, password reset, etc. It handles logging the users into your application using secure cookies (powered by express-session), and it also handles everything else.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;oktaClient&lt;/code&gt; object is merely used to retrieve user data from the Okta API service.&lt;/p&gt;

&lt;p&gt;Now that our OpenID Connect support is ready to be used, let’s enable it. To do this, open up the &lt;code&gt;./app.js&lt;/code&gt; and find the session middleware from earlier, then add the following line beneath it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(session({
  secret: 'asdf;lkjh3lkjh235l23h5l235kjh',
  resave: true,
  saveUninitialized: false
}));
app.use(oidc.router);

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;app.use(oidc.router);&lt;/code&gt; call is all that’s needed to tell Express.js to enable the routes that ship with the oidc-middleware library to handle all of the OpenID Connect support. You might have noticed above that when we created the &lt;code&gt;oidc&lt;/code&gt; object we specified some &lt;code&gt;routes&lt;/code&gt; in the configuration. These settings dictate what URLs we want to use to handle user login, and what URLs we want to redirect users to after they’ve been logged in.&lt;/p&gt;

&lt;p&gt;One benefit of this router being enabled is that from this point forward, in &lt;em&gt;any&lt;/em&gt; of our route code, we’ll have access to a special variable, &lt;code&gt;req.userinfo&lt;/code&gt;, which contains some of the currently logged in user’s basic profile information (pulled from Okta).&lt;/p&gt;

&lt;p&gt;And while &lt;code&gt;req.userinfo&lt;/code&gt; is nice, it’d be a lot nicer if we could get &lt;em&gt;any&lt;/em&gt; data about the currently logged in user that we want.&lt;/p&gt;

&lt;p&gt;So let’s go ahead and define another middleware to help us with that. Immediately below the &lt;code&gt;app.use(oidc.router);&lt;/code&gt; code, insert 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;app.use((req, res, next) =&amp;gt; {
  if (!req.userinfo) {
    return next();
  }

  oktaClient.getUser(req.userinfo.sub)
    .then(user =&amp;gt; {
      req.user = user;
      res.locals.user = user;
      next();
    }).catch(err =&amp;gt; {
      next(err);
    });
});

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

&lt;/div&gt;



&lt;p&gt;This middleware will run on every user request, and does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It checks to see if there is a currently logged in user or not by looking at the &lt;code&gt;req.userinfo&lt;/code&gt; object. If there is no user logged in, it will do nothing (&lt;code&gt;return next();&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;If there IS a user logged in, this middleware will then use the Okta Node SDK library to retrieve the user object from the Okta API.&lt;/li&gt;
&lt;li&gt;Finally, it will create two new values: &lt;code&gt;req.user&lt;/code&gt; and &lt;code&gt;res.locals.user&lt;/code&gt; which point to the user object directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means that in any route we define later on, we could access the &lt;code&gt;req.user&lt;/code&gt; object directly to view the user’s information, edit it, or even delete it.&lt;/p&gt;

&lt;p&gt;For example, you could create the following route below to display the user’s profile information each time a user visits the &lt;code&gt;/test&lt;/code&gt; URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/test', (req, res) =&amp;gt; {
  res.json({ profile: req.user ? req.user.profile : null });
});

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

&lt;/div&gt;



&lt;p&gt;Let’s also go ahead and create one additional middleware, &lt;code&gt;loginRequired&lt;/code&gt;, that will only allow a user to visit a route if they’ve been logged in already. This will come in handy if you want to build pages that only logged in users can access (a dashboard, etc.).&lt;/p&gt;

&lt;p&gt;Below the code above, go ahead and define the function below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function loginRequired(req, res, next) {
  if (!req.user) {
    return res.status(401).render("unauthenticated");
  }

  next();
}

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

&lt;/div&gt;



&lt;p&gt;Since we want to ensure only logged in users can view our dashboard page, let’s also go back and modify our route code for the dashboard.&lt;/p&gt;

&lt;p&gt;Find the line of code that enabled the dashboard route in your &lt;code&gt;./app.js&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;app.use('/dashboard', dashboardRouter);                       

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

&lt;/div&gt;



&lt;p&gt;Now modify it to look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use('/dashboard', loginRequired, dashboardRouter);

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

&lt;/div&gt;



&lt;p&gt;By injecting the &lt;code&gt;loginRequired&lt;/code&gt; function immediately after the URL pattern, Express.js will first run our &lt;code&gt;loginRequired&lt;/code&gt; middleware BEFORE the &lt;code&gt;dashboardRouter&lt;/code&gt; is processed. This way, if a user visits &lt;em&gt;any&lt;/em&gt; page that starts with the URL &lt;code&gt;/dashboard&lt;/code&gt; they’ll be required to log in before they can access it!&lt;/p&gt;

&lt;p&gt;The final thing we need to do to finish up our authentication component is define a logout route. The oidc-middleware library provides logout functionality, but doesn’t automatically generate a route for it.&lt;/p&gt;

&lt;p&gt;To do this, create a new file named &lt;code&gt;./routes/users.js&lt;/code&gt; and put the following code inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");

const router = express.Router();

// Log a user out
router.get("/logout", (req, res) =&amp;gt; {
  req.logout();
  res.redirect("/");
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;As you can probably tell, this route will log a user out of their account if they send a POST request to the &lt;code&gt;/users/logout&lt;/code&gt; URL. The only thing we need to do now is enable this route in our &lt;code&gt;./app.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;./app.js&lt;/code&gt;, and import this new route file alongside the others at the top of the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const dashboardRouter = require("./routes/dashboard");
const publicRouter = require("./routes/public");
const usersRouter = require("./routes/users");

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

&lt;/div&gt;



&lt;p&gt;Next, scroll down until you see your other routers being enabled, and enable this router as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use('/', publicRouter);
app.use('/dashboard', loginRequired, dashboardRouter);
app.use('/users', usersRouter);

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

&lt;/div&gt;



&lt;p&gt;Congratulations, you’ve now got user management and authentication fully configured for your website! And you didn’t even have to write any code, manage any passwords, store anything in a database, etc!&lt;/p&gt;

&lt;h2&gt;
  
  
  How Authentication Works
&lt;/h2&gt;

&lt;p&gt;Now that you’ve seen how to successfully setup authentication for your Node.js websites, let’s talk a bit more about &lt;em&gt;how&lt;/em&gt; it works and explore the full authentication flow.&lt;/p&gt;

&lt;p&gt;In order to explain each component, let’s assume that you’re visiting this website and are not currently logged into your account.&lt;/p&gt;

&lt;p&gt;When you first click the &lt;code&gt;Log In / Register&lt;/code&gt; button at the top of the page, the oidc-middleware library is going to redirect you to an Okta hosted domain (the authorization server). Here’s the sort of URL you’ll be redirected to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://dev-842917.oktapreview.com/login/login.htm?fromURI=/oauth2/v1/authorize/redirect?okta_key=qBpZVCpQIJlxUALtybnI9oajmFSOmWJNKL9pDpGtZRU

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : You can fully customize this domain name, look, and feel using Okta.&lt;/p&gt;

&lt;p&gt;Once you’ve landed on the authorization server page, you can either enter your account credentials and login immediately or create a new account. This functionality is handled by the authorization server completely.&lt;/p&gt;

&lt;p&gt;If you enter your credentials and click the &lt;strong&gt;Sign In&lt;/strong&gt; button on the authorization server, what happens behind the scenes is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your password is hashed and your credentials are checked against the Okta user database to determine whether or not they are correct&lt;/li&gt;
&lt;li&gt;If your credentials are correct, a new session cookie is created for you on the Okta hosted domain (eg: &lt;code&gt;dev-842917.oktapreview.com&lt;/code&gt;, in this case), and you are redirected to the &lt;code&gt;redirect_uri&lt;/code&gt; setting you provided earlier when defining the &lt;code&gt;ExpressOIDC&lt;/code&gt; object. In this case, you’d be redirected to &lt;code&gt;http://localhost:3000/users/callback&lt;/code&gt;. When you’re redirected to this URL, the authorization server will also pass along a special &lt;code&gt;code&lt;/code&gt; token. This is part of the &lt;a href="https://developer.okta.com/authentication-guide/implementing-authentication/auth-code" rel="noopener noreferrer"&gt;OpenID Connect Authorization Code flow&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Your Express.js app will receive the request to &lt;code&gt;/users/callback&lt;/code&gt; and service the request automatically using the oidc-middleware library’s built-in routes. The route servicing this URL will intercept the request and exchange the &lt;code&gt;code&lt;/code&gt; token for an &lt;code&gt;access&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; token. This process of exchanging the code token is part of the OpenID Connect authorization code flow and is detailed more here: &lt;a href="https://developer.okta.com/authentication-guide/implementing-authentication/auth-code#3-exchanging-the-code-for-tokens" rel="noopener noreferrer"&gt;/authentication-guide/implementing-authentication/auth-code#3-exchanging-the-code-for-tokens&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Once these tokens have been retrieved, the oidc-middleware library takes the user’s basic information embedded in the id token and stores it in a session cookie.&lt;/li&gt;
&lt;li&gt;Then, the oidc-middleware library redirects you to the dashboard page as a fully logged-in user.&lt;/li&gt;
&lt;li&gt;From this point on, each time your browser makes a request to the Express.js website, the cookie containing your profile information will be sent back to Express.js, so that the oidc-middleware library can recognize who you are and populate a &lt;code&gt;req.userinfo&lt;/code&gt; object with your account data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once your session cookies have expired (or have been wiped via a logout procedure), the process starts all over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Styles
&lt;/h2&gt;

&lt;p&gt;I’m not a professional designer, but even I can make this website look a little better.&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;./public/stylesheets/style.css&lt;/code&gt; and put the following CSS into it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.top-bar a {
 text-decoration: none;
  color: inherit;
}

footer {
  border-top: 1px solid rgba(0,0,0,.1);
  margin-top: 4em !important;
  padding-top: 1em;
  text-align: center;
  margin-top: 1em;
}

h2 {
  margin-bottom: 2em;
}

.container {
  padding-top: 2em;
}

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

&lt;/div&gt;



&lt;p&gt;This will make the page styles look a little nicer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Out Your New Login Portal
&lt;/h2&gt;

&lt;p&gt;Now that your Express.js website is built, why not take it for a test drive? Start up your web server by running the &lt;code&gt;npm start&lt;/code&gt; command, visit &lt;code&gt;http://localhost:3000&lt;/code&gt;, and test things out!&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%2Fbuild-understand-auth-node%2Fusing-the-site-local-37f57f615a88df903b03ecf76b3987f4eda2e346025ac5ef371398705e61d62c.gif" 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%2Fbuild-understand-auth-node%2Fusing-the-site-local-37f57f615a88df903b03ecf76b3987f4eda2e346025ac5ef371398705e61d62c.gif" alt="using the site locally"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you click the &lt;code&gt;Log In / Register&lt;/code&gt; button at the top of the page, you can either create a new user account OR log into an existing one. This functionality is all provided by Okta’s authorization server automatically.&lt;/li&gt;
&lt;li&gt;Once you’re logged in, you’ll be redirected to the &lt;code&gt;/dashboard&lt;/code&gt; page, which will greet you by your first name. Remember that &lt;code&gt;#{user.profile.firstName}&lt;/code&gt; variable in the &lt;code&gt;./views/dashboard.pug&lt;/code&gt; file earlier? That variable is now you actual user account since you’ve now plugged in all the appropriate middleware.&lt;/li&gt;
&lt;li&gt;If you log out, then immediately click the &lt;code&gt;Log In / Register&lt;/code&gt; button again, you’ll be instantly logged in without needing to re-enter your username and password. This is a feature of OpenID Connect — the authorization server remembers who you are for a set amount of time. This is the same way that Google Login and Facebook Login work!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re already logged into your Okta account and instantly get logged into the dashboard, don’t worry. Just open a new incognito window in your browser and go through the flow there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About Node.js and Authentication
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed seeing how authentication works with OpenID Connect and Node.js. Building websites with user management can be a pain, but new protocols like OpenID Connect alongside providers like &lt;a href="https://developer.okta.com" rel="noopener noreferrer"&gt;Okta&lt;/a&gt; make the process much simpler.&lt;/p&gt;

&lt;p&gt;If you’d like to learn more about building web apps in Node, you might want to check out these other great posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/05/18/node-authentication-with-passport-and-oidc" rel="noopener noreferrer"&gt;Build Secure Node Authentication with Passport.js and OpenID Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/02/06/build-user-registration-with-node-react-and-okta" rel="noopener noreferrer"&gt;Build User Registration with Node, React, and Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/04/24/simple-node-authentication" rel="noopener noreferrer"&gt;Simple Node Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/02/15/build-crud-app-vuejs-node" rel="noopener noreferrer"&gt;Build a Basic CRUD App with Vue.js and Node&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, please &lt;a href="https://twitter.com/OktaDev" rel="noopener noreferrer"&gt;follow us on Twitter&lt;/a&gt; to find more great resources like this, request other topics for us to write about, and follow along with our new open source libraries and projects!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt; : If you liked this project and want to see the source code in one place, please go checkout and star the &lt;a href="https://github.com/rdegges/okta-express-login-portal" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And… If you have any questions, please leave a comment below!&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Build a Simple CRUD App with Flask and Python</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Mon, 23 Jul 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/build-a-simple-crud-app-with-flask-and-python-16p1</link>
      <guid>https://dev.to/oktadev/build-a-simple-crud-app-with-flask-and-python-16p1</guid>
      <description>&lt;p&gt;Today I’m going to walk you through building a simple Flask web app (a blog) complete with user management (login, registration, etc.), database models, and everything else that goes along with it.&lt;/p&gt;

&lt;p&gt;In this post I’ll walk you through the code piece-by-piece, explaining everything you need to know along the way. By the end of this tutorial, you’ll know how to build simple Flask web apps and have a good understanding of how to create database models, add user registration and login to your sites, etc.&lt;/p&gt;

&lt;p&gt;Through this post you’ll learn about and use the following tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/pallets/flask"&gt;Flask&lt;/a&gt; — my favorite Python web framework. It’s small, minimal, and simple.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mitsuhiko/flask-sqlalchemy"&gt;Flask-SQLAlchemy&lt;/a&gt; — an extremely popular ORM for Flask. It allows you to interact with relational database servers like Postgres, MySQL, SQLite, etc. In this tutorial, we’ll be using SQLite as our database, but any of the others would work equally well with no code changes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/puiterwijk/flask-oidc"&gt;Flask-OIDC&lt;/a&gt; — an OpenID Connect library for Flask. &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1"&gt;OpenID Connect&lt;/a&gt; is an open protocol that handles user authentication and authorization. It’s the “modern” way to handle authentication on the web.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.okta.com/"&gt;Okta&lt;/a&gt; — a free-to-use API service that acts as an OpenID Connect authorization server. Okta will store user accounts for your app and make it possible to handle user registration, login, etc. in a simple way.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/un33k/python-slugify"&gt;python-slugify&lt;/a&gt; — a simple Python library that generates web-friendly URLs. We’ll use this to convert blog post titles into URLs that look nice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’d like to skip the tutorial and check out the fully built project, you can go &lt;a href="https://github.com/rdegges/okta-flask-blog"&gt;view it on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize Authentication for Your Flask + Python App with Okta
&lt;/h2&gt;

&lt;p&gt;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 OpenID Connect to make integration seamless.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll use Okta to store the user accounts for your web app, and you’ll use OpenID Connect to talk to Okta to handle the logistics around authentication and authorization.&lt;/p&gt;

&lt;p&gt;To get started, you first need to create a free Okta developer account: &lt;a href="https://developer.okta.com/signup/"&gt;https://developer.okta.com/signup/&lt;/a&gt;. Once you’ve created your account and logged in, follow the steps below configure Okta, and then you’ll be ready to write some code!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HGS919ZQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-registration-page-ee14e7516bdc7df3e6e950a2c385706754c5300d842a1374785fd9e43cab2a6b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HGS919ZQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-registration-page-ee14e7516bdc7df3e6e950a2c385706754c5300d842a1374785fd9e43cab2a6b.png" alt="Okta registration page" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Store Your Org URL
&lt;/h3&gt;

&lt;p&gt;The first thing you need to do is copy down the &lt;strong&gt;Org URL&lt;/strong&gt; from the top-right portion of your Okta dashboard page. This URL will be used to route to your authorization server, communicate with it, and much more. You’ll need this value later, so don’t forget it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--On5DcBRb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-org-url-b26a98af3fa71a8f88519b5154d16d10fae846ff3df95d09995fcd61fa2c6175.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--On5DcBRb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-org-url-b26a98af3fa71a8f88519b5154d16d10fae846ff3df95d09995fcd61fa2c6175.png" alt="Okta org URL" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create an OpenID Connect Application
&lt;/h3&gt;

&lt;p&gt;Okta allows you to store and manage users for multiple applications you might be creating. This means that before we can go any further, you need to create a new OpenID Connect application for this project.&lt;/p&gt;

&lt;p&gt;Applications in OpenID Connect have a username and password (referred to as a client ID and client secret) that allow your authorization server to recognize which application is talking to it at any given time.&lt;/p&gt;

&lt;p&gt;To create a new application browse to the &lt;strong&gt;Applications&lt;/strong&gt; tab and click &lt;strong&gt;Add Application&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tB0Z0ra1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-application-page-5d3d0ee99d0d6888f30bffc5fa3d58ddaafe907dfd2ec315589435b2fc7bb23b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tB0Z0ra1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-application-page-5d3d0ee99d0d6888f30bffc5fa3d58ddaafe907dfd2ec315589435b2fc7bb23b.png" alt="Okta application page" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click the &lt;strong&gt;Web&lt;/strong&gt; platform option (since this project is a web app).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D3cx6RTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-create-application-page-681dcd71ac7de879a92e80d243020f9c9be6edc17e6ae0b0adb40a70936eac24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D3cx6RTn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-create-application-page-681dcd71ac7de879a92e80d243020f9c9be6edc17e6ae0b0adb40a70936eac24.png" alt="Okta create application page" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the settings page, enter the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; : Simple Flask App&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:5000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login redirect URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:5000/oidc/callback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can leave all the other values unchanged.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XvHl_L3W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-create-application-settings-page-1daaf2e72b07b2771b7197f04366cc59f3245a538fbcdb75ccec503494ebd681.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XvHl_L3W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-create-application-settings-page-1daaf2e72b07b2771b7197f04366cc59f3245a538fbcdb75ccec503494ebd681.png" alt="Okta create application settings page" width="800" height="870"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that your application has been created, copy down the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client secret&lt;/strong&gt; values on the following page, you’ll need them later when we start writing code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5KqUDjpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-application-credentials-page-2f5b916ff40dc7425e731c801f9b087342846ed828a7979ab79127059d67d6b3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5KqUDjpH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-application-credentials-page-2f5b916ff40dc7425e731c801f9b087342846ed828a7979ab79127059d67d6b3.png" alt="Okta application credentials page" width="729" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create an Authentication Token
&lt;/h3&gt;

&lt;p&gt;To access the Okta APIs and be able to manage your user accounts with a great deal of granularity, you’ll also need to create an Okta authentication token. This is an API key that will be used later on communicate with the Okta APIs and allows you to do things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create, update, and delete users&lt;/li&gt;
&lt;li&gt;Create, update, and delete groups&lt;/li&gt;
&lt;li&gt;Manage application settings&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create an authentication token click the &lt;strong&gt;API&lt;/strong&gt; tab at the top of the page followed by the &lt;strong&gt;Create Token&lt;/strong&gt; button. Give your token a name, preferably the same name as your application, then click &lt;strong&gt;Create Token&lt;/strong&gt;. Once your token has been created, copy down the token value as you will need it later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I7lvawHW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-create-token-page-008a4364f7541ac93b9baf5d3b381ba889bd7188fd6101b19901f0cdf9821a6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I7lvawHW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-create-token-page-008a4364f7541ac93b9baf5d3b381ba889bd7188fd6101b19901f0cdf9821a6c.png" alt="Okta create token page" width="592" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Enable User Registration
&lt;/h3&gt;

&lt;p&gt;The last piece of setup you need to complete is to enable user registration functionality for the authorization server. Typically, authorization servers only support login, logout, and stuff like that. But Okta’s authorization server also supports self-service registration, so that users can create accounts, log into them, reset passwords, and basically do everything without you writing any code for it.&lt;/p&gt;

&lt;p&gt;In your Okta dashboard, you’ll notice a small button labeled &lt;strong&gt;&amp;lt; &amp;gt; Developer Console&lt;/strong&gt; at the top-left of your page. Hover over that button and select the &lt;strong&gt;Classic UI&lt;/strong&gt; menu option that appears.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QYwlu17m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-classic-ui-dropdown-249d1b924c3db38af5d62bf17be65a32579117d9d23c8c28cb7e365eba7d8f85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QYwlu17m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-classic-ui-dropdown-249d1b924c3db38af5d62bf17be65a32579117d9d23c8c28cb7e365eba7d8f85.png" alt="Okta classic UI dropdown" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, hover over the &lt;strong&gt;Directory&lt;/strong&gt; tab at the top of the page then select the &lt;strong&gt;Self-Service Registration&lt;/strong&gt; menu item. On this page click the &lt;strong&gt;Enable Registration&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2ieCMABP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-enable-self-service-registration-page-2cfef05884c196fa53bc7c55728c77437713fffa5d549e1874e18c2593825b1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2ieCMABP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-enable-self-service-registration-page-2cfef05884c196fa53bc7c55728c77437713fffa5d549e1874e18c2593825b1f.png" alt="Okta enable self-service registration page" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the configuration page, leave all the settings as their default values, except for two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disable the &lt;strong&gt;User must verify email address to be activated.&lt;/strong&gt; checkbox. This setting removes the requirement for new users to verify their email address before being allowed to access your web app.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Default redirect&lt;/strong&gt; option by clicking the &lt;strong&gt;Custom URL&lt;/strong&gt; radio box and entering &lt;code&gt;http://localhost:5000/dashboard&lt;/code&gt; as the value. This setting tells the authorization server where to redirect users after they’ve successfully created a new account on your site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve clicked &lt;strong&gt;Save&lt;/strong&gt; , the last thing you need to is switch back to the developer console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--As9sw7nn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-self-service-registration-settings-page-c39b81450dd9cf108d58625f7552da1982902c7ff175e737396e051be29f19e8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--As9sw7nn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/okta-self-service-registration-settings-page-c39b81450dd9cf108d58625f7552da1982902c7ff175e737396e051be29f19e8.png" alt="Okta enable self-service registration settings page" width="800" height="838"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hover over the &lt;strong&gt;Classic UI&lt;/strong&gt; button at the top right of the page and select the &lt;strong&gt;&amp;lt; &amp;gt; Developer Console&lt;/strong&gt; menu item from the drop-down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Python and Flask Dependencies
&lt;/h2&gt;

&lt;p&gt;The first thing you need to do to initialize your Flask app is install all of the required dependencies. If you don’t have Python installed on your computer already, please go &lt;a href="https://www.python.org/downloads/"&gt;install it now&lt;/a&gt;. Be sure to use the latest Python 3+ release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : I also strongly recommend you get familiar with &lt;a href="https://docs.pipenv.org/"&gt;pipenv&lt;/a&gt; when you get some time. It’s a great tool that makes managing Python dependencies very simple.&lt;/p&gt;

&lt;p&gt;Now install the dependencies required for this application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install Flask==1.0.2
pip install Flask-SQLAlchemy==2.3.2
pip install flask-oidc==1.4.0
pip install python-slugify==1.2.5
pip install okta==0.0.4

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialize Your Flask App
&lt;/h2&gt;

&lt;p&gt;Now that the dependencies are installed, let’s start by creating a simple Flask app. We’ll build on this simple “hello, world!” app until we’ve got all our functionality included.&lt;/p&gt;

&lt;p&gt;First, create a new directory for your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir simple-flask-app
cd simple-flask-app

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

&lt;/div&gt;



&lt;p&gt;Next, create a directory inside your project to hold your Flask application code. This folder will hold all the project source code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir blog

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

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;blog/ __init__.py&lt;/code&gt; file and enter the following code. This file will hold your Flask app’s initialization code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask

app = Flask( __name__ )

@app.route("/")
def index():
    return "hello, world!"

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

&lt;/div&gt;



&lt;p&gt;Open the terminal and run the following code to start up your new Flask app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FLASK_APP=blog flask run

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

&lt;/div&gt;



&lt;p&gt;Once your Flask app is running, visit &lt;code&gt;http://localhost:5000&lt;/code&gt; in the browser to see the hello world message!&lt;/p&gt;

&lt;p&gt;As you can see from the small file above, building a minimalist app with Flask can be really simple. All you need to do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import the Flask library&lt;/li&gt;
&lt;li&gt;Create a Flask app object&lt;/li&gt;
&lt;li&gt;Define a function (called a view) that runs when a particular URL is requested by a user (in this case, the &lt;code&gt;/&lt;/code&gt; URL)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not bad, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Flask Templates
&lt;/h2&gt;

&lt;p&gt;I’m primarily a back-end developer. I do some basic front-end work, but it isn’t my strong suit. Because of this, I like to get the tough stuff out of the way first, and in my case, that tough stuff is &lt;em&gt;templating&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When building a website with Flask, you’ll usually use the built-in &lt;a href="http://jinja.pocoo.org/docs/2.10/"&gt;Jinja2&lt;/a&gt; templating language.&lt;/p&gt;

&lt;p&gt;You can think of Jinja2 as HTML with a little bit of extra stuff: variables, filters, and some other tools that make building large websites simpler. I find Jinja2 simple to work with, and once you get the hang of it, I’m sure you’ll like it too.&lt;/p&gt;

&lt;p&gt;To get started creating the templates, let’s create the necessary template files which we’ll fill in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p blog/static
touch simple-flask-app/blog/static/style.css
mkdir -p blog/templates/blog
touch blog/templates/{403.html,404.html,layout.html}
touch blog/templates/blog/{dashboard.html,edit.html,index.html,post.html}

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

&lt;/div&gt;



&lt;p&gt;You should now have the following directory structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;simple-flask-app
└── blog
    ├── __init__.py
    ├── static
    │ └── style.css
    └── templates
        ├── 403.html
        ├── 404.html
        ├── blog
        │ ├── dashboard.html
        │ ├── edit.html
        │ ├── index.html
        │ └── post.html
        └── layout.html

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;templates&lt;/code&gt; folder holds all of the project’s templates. Within that folder there are some “top-level” templates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;layout.html&lt;/code&gt; — this template is the base for all other templates. It contains all the boilerplate HTML code, etc. that all the other pages will share in common with each other.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;403.html&lt;/code&gt; — this template will be shown to the user if they get a 403 error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;404.html&lt;/code&gt; — this template will be shown to the user if they get a 404 error&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;static/&lt;/code&gt; — this folder holds all the static files for the site (images, CSS, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;static/style.css&lt;/code&gt; — this file holds all the website styles&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog/&lt;/code&gt; — this folder holds all the blog-related templates&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog/index.html&lt;/code&gt; — the blog homepage&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog/dashboard.html&lt;/code&gt; — the user dashboard&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog/edit.html&lt;/code&gt; — the post edit page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;blog/post.html&lt;/code&gt; — the page that shows a single post&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, copy the following CSS into the &lt;code&gt;blog/static/style.css&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;footer {
  text-align: center;
  font-style: italic;
  margin-top: 1em;
}

.nav {
  float: right;
}

h2 {
  margin-bottom: 2em;
}

.posts ul {
  list-style-type: none;
}

.posts a {
  font-size: 1.3em;
  text-decoration: underline;
  color: #212529;
}

.posts span {
  font-size: 1.1em;
  float: right;
}

.empty {
  font-size: 2em;
  margin-bottom: 5em;
}

.container {
  padding-top: 2em;
}

.unauthenticated p {
  font-size: 1.3em;
  text-align: center;
}

hr.bottom {
  margin-top: 4em;
}

.submit-btn {
  float: right;
}

.alert p {
  font-size: 1.1em;
}

.author {
  font-size: 1.2em;
  margin-top: 2em;
}

.body {
  margin-top: 2em;
  font-size: 1.2em;
}

.edit {
  padding-left: 0;
}

.edit a {
  text-decoration: underline;
  color: #212529;
  font-size: 1.5em;
}

.edit li {
  list-style-type: none;
  line-height: 2.5em;
}

.edit button {
  float: right;
}

.delete {
  margin-left: 1em;
}

.your-posts {
  margin-top: 2em;
}

.hidden {
  display: inline;
}

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

&lt;/div&gt;



&lt;p&gt;I won’t explain this as I assume you’re familiar with CSS. I’ve basically just defined some simple styles that will come into play later.&lt;/p&gt;

&lt;p&gt;Next, let’s create the &lt;code&gt;blog/templates/layout.html&lt;/code&gt; template. This template contains reusable HTML that all the other pages of the site will share.&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;!doctype html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"&amp;gt;
    &amp;lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous"&amp;gt;
    &amp;lt;link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"&amp;gt;
    &amp;lt;title&amp;gt;Blog | {% block title %}{% endblock %}&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom box-shadow"&amp;gt;
      &amp;lt;h5 class="my-0 mr-md-auto font-weight-normal"&amp;gt;Blog&amp;lt;/h5&amp;gt;
      &amp;lt;nav class="my-2 my-md-0 mr-md-3"&amp;gt;
        &amp;lt;a class="p-2 text-dark" href="/" title="Home"&amp;gt;Home&amp;lt;/a&amp;gt;
        {% if not g.user %}
          &amp;lt;a class="p-2 text-dark" href="/login"&amp;gt;Log In / Register&amp;lt;/a&amp;gt;
        {% else %}
          &amp;lt;a class="p-2 text-dark" href="/dashboard"&amp;gt;Dashboard&amp;lt;/a&amp;gt;
          &amp;lt;a class="p-2 text-dark" href="/logout"&amp;gt;Logout&amp;lt;/a&amp;gt;
        {% endif %}
      &amp;lt;/nav&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="container"&amp;gt;
      {% block body %}{% endblock %}
    &amp;lt;/div&amp;gt;
    &amp;lt;footer class="text-center"&amp;gt;Created by &amp;lt;a href="https://twitter.com/rdegges"&amp;gt;@rdegges&amp;lt;/a&amp;gt;, built using &amp;lt;a href="https://twitter.com/okta"&amp;gt;@okta&amp;lt;/a&amp;gt;.
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Most of this page is just standard HTML. You can see with a quick glance that there’s a head tag that includes the &lt;a href="https://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt; UI library (to make things look decent), a navbar that will show on all the pages of the site, and a footer. Other than that, there are a couple of key elements that make this template special. Let’s analyze them.&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;link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;The link tag in the head section above uses a special function, &lt;code&gt;url_for&lt;/code&gt;, to properly link to the &lt;code&gt;style.css&lt;/code&gt; file you created above. This is a built-in Flask function that figures out what URL the static files will be served at based on your Flask configuration. This is a lot nicer than if you would have hardcoded something like &lt;code&gt;/static/style.css&lt;/code&gt;, since at any point in the future you can change a Flask setting and move all your static files to a new URL.&lt;/p&gt;

&lt;p&gt;You may have also noticed the special blog tags:&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;title&amp;gt;Blog | {% block title %}{% endblock %}&amp;lt;/title&amp;gt;

&amp;lt;!-- ... --&amp;gt;

{% block body %}{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;These special &lt;code&gt;block&lt;/code&gt; tags act as a placeholder for future values. Since this template will be reused across every page of our site, it would be silly if each page of the site had to have the exact same title or same body content. To work around this, you can use the &lt;code&gt;block&lt;/code&gt; tag shown above. Child templates will be able to insert their own titles and body content into this template to generate a full page without duplicating code!&lt;/p&gt;

&lt;p&gt;Lastly, take a look at the navbar code and the &lt;code&gt;if/else&lt;/code&gt; statement it contains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% if not g.user %}
  &amp;lt;a class="p-2 text-dark" href="/login"&amp;gt;Log In / Register&amp;lt;/a&amp;gt;
{% else %}
  &amp;lt;a class="p-2 text-dark" href="/dashboard"&amp;gt;Dashboard&amp;lt;/a&amp;gt;
  &amp;lt;a class="p-2 text-dark" href="/logout"&amp;gt;Logout&amp;lt;/a&amp;gt;
{% endif %}

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

&lt;/div&gt;



&lt;p&gt;This is a Jinja2 conditional block, which works intuitively. If the variable &lt;code&gt;g.user&lt;/code&gt; does not exist, then the user will be shown a button in the navbar that prompts them to login or register. Otherwise, the user will be shown a Dashboard and Logout button instead.&lt;/p&gt;

&lt;p&gt;In the future, the &lt;code&gt;g.user&lt;/code&gt; variable will contain a logged-in user account (if one exists), which is what this conditional will be checking against. But more on that later!&lt;/p&gt;

&lt;p&gt;Next, go ahead and copy the following code into the &lt;code&gt;blog/templates/403.html&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}Insufficient Permissions{% endblock %}

{% block body %}
  &amp;lt;h1 class="text-center"&amp;gt;Insufficient Permissions&amp;lt;/h1&amp;gt;
  &amp;lt;p class="text-center"&amp;gt;Mind your own business &amp;amp;gt;:S&amp;lt;/p&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;This is what a child template looks like. It uses the special &lt;code&gt;extends&lt;/code&gt; tag to literally “extend” the &lt;code&gt;layout.html&lt;/code&gt; template you just created.&lt;/p&gt;

&lt;p&gt;In this template, the content between the &lt;code&gt;block&lt;/code&gt; tags is inserted into the parent template (&lt;code&gt;layout.html&lt;/code&gt;) as specified. This template, when rendered, will now display a full page without needing to duplicate any code. Pretty neat!&lt;/p&gt;

&lt;p&gt;Next, copy the following code into the &lt;code&gt;blog/templates/404.html&lt;/code&gt; file. This page will be shown to a user when they visit a page that isn’t found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}Page Not Found{% endblock %}

{% block body %}
  &amp;lt;h1 class="text-center"&amp;gt;Page Not Found&amp;lt;/h1&amp;gt;
  &amp;lt;p class="text-center"&amp;gt;Whatever you did, it's not working :(&amp;lt;/p&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;Now copy the following code into the &lt;code&gt;blog/templates/blog/index.html&lt;/code&gt; file. This template will be the homepage for the blog app we’re creating. It will list the blog posts so readers can view them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}Home{% endblock %}

{% block body %}
  &amp;lt;h2 class="text-center"&amp;gt;Recent Posts&amp;lt;/h2&amp;gt;
  {% if posts %}
    &amp;lt;div class="posts"&amp;gt;
      &amp;lt;ul&amp;gt;
        {% for post in posts %}
          &amp;lt;div class="row"&amp;gt;
            &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
              &amp;lt;li&amp;gt;
                &amp;lt;a href="/{{ post.slug }}" title="{{ post.title }}"&amp;gt;{{ post.title }} &amp;lt;span&amp;gt;  by {{ post.author_name }}&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        {% endfor %}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  {% else %}
    &amp;lt;p class="empty text-center"&amp;gt;Uh-oh. There are no posts to view.&amp;lt;/p&amp;gt;
  {% endif %}
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;Note that this template uses the &lt;code&gt;for&lt;/code&gt; tag to loop through an array of &lt;code&gt;post&lt;/code&gt; objects, and then generates links to each of the blog posts by using the &lt;code&gt;post&lt;/code&gt; object properties, e.g. &lt;code&gt;post.author_name&lt;/code&gt;, &lt;code&gt;post.title&lt;/code&gt;, etc. Using the &lt;code&gt;{{ ... }}&lt;/code&gt; syntax allows you to output a variable’s value into the HTML of the page.&lt;/p&gt;

&lt;p&gt;Now copy the following code into the &lt;code&gt;blog/templates/blog/dashboard.html&lt;/code&gt; file. This will be the dashboard that authors can use to manage their articles. It will allow them to create articles, edit articles, and delete articles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}Dashboard{% endblock %}

{% block body %}
  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
      &amp;lt;h2&amp;gt;Create a Post&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  {% if post %}
    &amp;lt;div class="row"&amp;gt;
     &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
       &amp;lt;div class="alert alert-successful text-center" role="alert"&amp;gt;
         &amp;lt;p&amp;gt;Your new post was created successfully! &amp;lt;a href="/{{ post.slug }}"&amp;gt;View it?&amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  {% endif %}

   &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
      &amp;lt;form method="post"&amp;gt;
        &amp;lt;div class="form-group"&amp;gt;
          &amp;lt;label for="title"&amp;gt;Post Title&amp;lt;/label&amp;gt;
          &amp;lt;input class="form-control" id="title" type="text" name="title" placeholder="Title" required&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class="form-group"&amp;gt;
          &amp;lt;label for="title"&amp;gt;Post Body&amp;lt;/label&amp;gt;
          &amp;lt;textarea class="form-control" id="post" name="body" rows="6" required&amp;gt;&amp;lt;/textarea&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;button class="btn btn-primary submit-btn" type="submit"&amp;gt;Update&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
      &amp;lt;h2 class="your-posts"&amp;gt;Your Posts&amp;lt;/h2&amp;gt;
      &amp;lt;ul class="edit"&amp;gt;
        {% for post in posts %}
          &amp;lt;li&amp;gt;
            &amp;lt;a href="/{{ post.slug }}" title="{{ post.title }}"&amp;gt;{{ post.title }}&amp;lt;/a&amp;gt;
            &amp;lt;form class="hidden" method="post" action="/{{ post.slug }}/delete"&amp;gt;
              &amp;lt;button class="btn btn-outline-danger delete"&amp;gt;Delete&amp;lt;/button&amp;gt;
            &amp;lt;/form&amp;gt;
            &amp;lt;a href="/{{ post.slug }}/edit" title="{{ post.title }}"&amp;gt;
              &amp;lt;button class="btn btn-outline-secondary"&amp;gt;Edit&amp;lt;/button&amp;gt;
            &amp;lt;/a&amp;gt;
          &amp;lt;/li&amp;gt;
        {% endfor %}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;Let’s continue by copy the following code into the &lt;code&gt;blog/templates/blog/edit.html&lt;/code&gt; file. This template will be displayed to the user when they want to edit one of their articles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}{{ post.title }}{% endblock %}

{% block body %}
  &amp;lt;h2 class="text-center"&amp;gt;Edit Post&amp;lt;/h2&amp;gt;
  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
      &amp;lt;form method="post"&amp;gt;
        &amp;lt;div class="form-group"&amp;gt;
          &amp;lt;label for="title"&amp;gt;Post Title&amp;lt;/label&amp;gt;
          &amp;lt;input class="form-control" id="title" type="text" name="title" value="{{ post.title }}" required&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class="form-group"&amp;gt;
          &amp;lt;label for="title"&amp;gt;Post Body&amp;lt;/label&amp;gt;
          &amp;lt;textarea class="form-control" id="post" name="body" rows="6" required&amp;gt;{{ post.body }}&amp;lt;/textarea&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;button class="btn btn-primary submit-btn" type="submit"&amp;gt;Update&amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;And finally, copy the code below into the &lt;code&gt;blog/templates/blog/post.html&lt;/code&gt; file. This template will be shown to the user when they attempt to view a blog post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}{{ post.title }}{% endblock %}

{% block body %}
  &amp;lt;h2 class="text-center"&amp;gt;{{ post.title }}&amp;lt;/h2&amp;gt;
  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="offset-sm-2 col-sm-8"&amp;gt;
      &amp;lt;div class="body"&amp;gt;{{ post.body|safe }}&amp;lt;/div&amp;gt;
      &amp;lt;p class="author"&amp;gt;Written by {{ post.author_name }}&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;And with that, we’re now done creating the templates! Yey!&lt;/p&gt;

&lt;p&gt;Now you can’t test this out just yet (we haven’t written any code to make this stuff work), but don’t worry, we’ll get there soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Database Models for Your Flask + Python App
&lt;/h2&gt;

&lt;p&gt;The next thing we’ll do is create the necessary database models for the application.&lt;/p&gt;

&lt;p&gt;Once the front-end templates have been built, the next complex part of an application is the data model. What data will your app be storing and referencing? I like to define these models early, so I know how to plug things together later on as the application evolves.&lt;/p&gt;

&lt;p&gt;For this app, we’ll be building a simple blog. This means we’ll primarily be storing two pieces of data: user account data and blog post data. Because we’ll be using OpenID Connect and Okta to store our user account data, that leaves just the blog post data for us to store and manage.&lt;/p&gt;

&lt;p&gt;A blog post in our application will require several critical pieces of data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;id&lt;/code&gt; field, so we can assign each blog post a unique identifier in the database&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;author_id&lt;/code&gt; field, so we can see what author created a blog post&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;created&lt;/code&gt; field, so we can see at what date and time a blog post was created&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;title&lt;/code&gt; field, so we can see what the title of each blog post is&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;body&lt;/code&gt; field, so we can see what the content of each blog post is (this will be HTML)&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;slug&lt;/code&gt; field, so we can determine what URL to display each blog post as (for example, a blog post titled “My Favorite Post” might be available at the URL &lt;a href="https://ourblog.com/my-favorite-post"&gt;https://ourblog.com/my-favorite-post&lt;/a&gt;, so “my-favorite-post” would be the slug)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we know what pieces of data are critical to store, let’s set up Flask-SQLAlchemy (the ORM library we’ll use to manage the database) as well as our database model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize Flask-SQLAlchemy
&lt;/h3&gt;

&lt;p&gt;To get our database hooked up, the first step is getting Flask-SQLAlchemy working.&lt;/p&gt;

&lt;p&gt;Create a new file, &lt;code&gt;blog/db.py&lt;/code&gt; and copy in the following code. This file will hold all of our database related code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from datetime import datetime

from click import command, echo
from flask_sqlalchemy import SQLAlchemy
from flask.cli import with_appcontext

# Initialize SQLAlchemy with no settings
db = SQLAlchemy()

@command("init-db")
@with_appcontext
def init_db_command():
    """Initialize the database."""
    db.create_all()
    echo("Initialized the database.")

def init_app(app):
    """Initialize the Flask app for database usage."""
    db.init_app(app)
    app.cli.add_command(init_db_command)

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

&lt;/div&gt;



&lt;p&gt;Let’s take a look at what’s happening here.&lt;/p&gt;

&lt;p&gt;First, we’re creating a &lt;code&gt;db&lt;/code&gt; global object. This is what will be used to create our database models later and manage our relationship with the database. When we initialize the &lt;code&gt;db&lt;/code&gt; object, we’re initializing the Flask-SQLAlchemy extension without actually giving it any settings or configuration. We’ll get to that soon.&lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;init_db_command&lt;/code&gt; function. This is a special command that you will be able to run on the command line when you type 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;FLASK_APP=blog flask init-db

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

&lt;/div&gt;



&lt;p&gt;This command runs a special method SQLAlchemy provides called &lt;code&gt;create_all&lt;/code&gt;, which will initialize any database tables and configuration specified. Right now this won’t do anything, but once we define database models in a moment, this will become useful.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;init_db_command&lt;/code&gt; function is built using the &lt;a href="http://click.pocoo.org/5/"&gt;click&lt;/a&gt; library which ships with Flask. click is a very popular library for building command line applications, like this one.&lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;init_app&lt;/code&gt; function. This is meant to run from the main application initialization code, and it will properly configure the Flask-SQLAlchemy extension as well as hook up the &lt;code&gt;init_db_command&lt;/code&gt; function to the app in the correct way.&lt;/p&gt;

&lt;p&gt;Now that our database code has been written, copy the following code into the &lt;code&gt;blog/ __init__.py&lt;/code&gt; file, overwriting what was there before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from os.path import dirname, join

from flask import Flask

from . import db

app = Flask( __name__ )
app.config.from_mapping(
    SQLALCHEMY_DATABASE_URI="sqlite:///" + join(dirname(dirname( __file__ )), "database.sqlite"),
)

db.init_app(app)

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

&lt;/div&gt;



&lt;p&gt;What we’re doing here, in the “main” part of our application, is importing the newly created database model we built a moment ago (&lt;code&gt;blog/db.py&lt;/code&gt;), specifying some application configuration data (to tell Flask-SQLAlchemy what sort of database we’re using), and finally, calling the special &lt;code&gt;db.init_app()&lt;/code&gt; function we defined in the &lt;code&gt;blog/db.py&lt;/code&gt; file, which initializes Flask-SQLAlchemy properly.&lt;/p&gt;

&lt;p&gt;For almost all Flask apps, you’ll at some point need to specify some configuration information that gets used by extensions or helper libraries. The way you do this is via the &lt;code&gt;app.config.from_mapping&lt;/code&gt; call above. This method allows you to define configuration data and settings that can be shared across your Flask app.&lt;/p&gt;

&lt;p&gt;In this case, we’re specifying a setting that Flask-SQLAlchemy requires, &lt;code&gt;SQLALCHEMY_DATABASE_URI&lt;/code&gt;, which basically tells it what type of database we’re using and how to access it. In this case, we’re going to be storing the SQLite database in a file called &lt;code&gt;database.sqlite&lt;/code&gt; in the root of our project folder.&lt;/p&gt;

&lt;p&gt;For this blog app, we’ll be using the &lt;a href="https://www.sqlite.org/index.html"&gt;SQLite database&lt;/a&gt;. SQLite is an incredibly popular database that stores all of its data in a single file on the disk. This makes it ideal for building portable applications. If you are building something that requires high levels of throughput and data processing, SQLite may not be the best fit… But for just about everything else, it’s not only simple — it’s very convenient, as you don’t even need a database server!&lt;/p&gt;

&lt;p&gt;Now, if you go back and re-run your Flask application, you’ll notice that it should run fine. The only problem is that we still haven’t accomplished anything yet other than initializing the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the SQLAlchemy Database Models
&lt;/h3&gt;

&lt;p&gt;Now that our database is initialized, let’s create the actual data model we need. This model will allow us to store blog post data as previously described into the SQLite database.&lt;/p&gt;

&lt;p&gt;Open up &lt;code&gt;blog/db.py&lt;/code&gt; and insert the following code, overwriting what was there before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from datetime import datetime

from click import command, echo
from flask_sqlalchemy import SQLAlchemy
from flask.cli import with_appcontext

# Initialize SQLAlchemy with no settings
db = SQLAlchemy()

class Post(db.Model):
    """A blog post."""
    id = db.Column(db.Integer, primary_key=True)
    author_id = db.Column(db.Text, nullable=False)
    created = db.Column(db.DateTime, default=datetime.utcnow)
    title = db.Column(db.Text, nullable=False)
    body = db.Column(db.Text, nullable=False)
    slug = db.Column(db.Text, nullable=False, unique=True)

@command("init-db")
@with_appcontext
def init_db_command():
    """Initialize the database."""
    db.create_all()
    echo("Initialized the database.")

def init_app(app):
    """Initialize the Flask app for database usage."""
    db.init_app(app)
    app.cli.add_command(init_db_command)

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

&lt;/div&gt;



&lt;p&gt;What we’ve added here is the new &lt;code&gt;Post&lt;/code&gt; class. This is a database model that tells SQLAlchemy what sort of data we’re storing (a blog post), and what fields it contains. To do this, we’re using typical relational database column types (Integer, Text, DateTime, etc.). If you aren’t familiar with SQL, you might want to check out this &lt;a href="https://www.khanacademy.org/computing/computer-programming/sql"&gt;fantastic Khan Academy course&lt;/a&gt; on the subject.&lt;/p&gt;

&lt;p&gt;Now that the database model has been defined, all we need to do is initialize the database so we can start writing and reading data from it. To do this, let’s use the new &lt;code&gt;init-db&lt;/code&gt; command we created earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FLASK_APP=blog flask init-db

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

&lt;/div&gt;



&lt;p&gt;If you look in the root of your project folder, you’ll now see a file called &lt;code&gt;database.sqlite&lt;/code&gt;. This is where all of your application data will now be stored!&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up User Registration, User Login, etc. in Flask
&lt;/h2&gt;

&lt;p&gt;Your database is now ready for action, but you still have a problem: how do you allow users to log into your website, create accounts, etc.? The answer is simple: OpenID Connect and &lt;a href="https://developer.okta.com/"&gt;Okta&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an OpenID Connect Config File
&lt;/h3&gt;

&lt;p&gt;Create a new file named &lt;code&gt;client_secrets.json&lt;/code&gt; in the root of your project folder and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "web": {
    "client_id": "{{ OKTA_CLIENT_ID }}",
    "client_secret": "{{ OKTA_CLIENT_SECRET }}",
    "auth_uri": "{{ OKTA_ORG_URL }}/oauth2/default/v1/authorize",
    "token_uri": "{{ OKTA_ORG_URL }}/oauth2/default/v1/token",
    "issuer": "{{ OKTA_ORG_URL }}/oauth2/default",
    "userinfo_uri": "{{ OKTA_ORG_URL }}/oauth2/default/userinfo",
    "redirect_uris": [
      "http://localhost:5000/oidc/callback"
    ]
  }
}

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

&lt;/div&gt;



&lt;p&gt;Be sure to replace the placeholder variables with your actual Okta information.&lt;/p&gt;

&lt;p&gt;Replace &lt;code&gt;{{ OKTA_ORG_URL }}&lt;/code&gt; with the Org URL on your dashboard pageReplace &lt;code&gt;{{ OKTA_CLIENT_ID }}&lt;/code&gt; with the Client ID on your application pageReplace &lt;code&gt;{{ OKTA_CLIENT_SECRET }}&lt;/code&gt; with the Client secret on your application page&lt;/p&gt;

&lt;p&gt;This file will be used by the Flask-OIDC library which we’ll be configuring in a moment. These settings essentially tell the OpenID Connect library what OpenID Connect application you’re using to authenticate against, and what your authorization server API endpoints are.&lt;/p&gt;

&lt;p&gt;The URIs above point to your newly created Okta resources so that the Flask library will be able to talk to it properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Flask-OIDC
&lt;/h3&gt;

&lt;p&gt;Open up &lt;code&gt;blog/ __init__.py&lt;/code&gt; and paste in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from os.path import dirname, join

from flask import Flask, g

from . import auth, db

app = Flask( __name__ )
app.config.from_mapping(
    SECRET_KEY={{ LONG_RANDOM_STRING }},
    OIDC_CLIENT_SECRETS=join(dirname(dirname( __file__ )), "client_secrets.json"),
    OIDC_COOKIE_SECURE=False,
    OIDC_CALLBACK_ROUTE="/oidc/callback",
    OIDC_SCOPES=["openid", "email", "profile"],
    OIDC_ID_TOKEN_COOKIE_NAME="oidc_token",
    SQLALCHEMY_DATABASE_URI="sqlite:///" + join(dirname(dirname( __file__ )), "database.sqlite"),
)

auth.oidc.init_app(app)
db.init_app(app)

app.register_blueprint(auth.bp)

@app.before_request
def before_request():
    """
    Load a user object into `g.user` before each request.
    """
    if auth.oidc.user_loggedin:
        g.user = auth.okta_client.get_user(auth.oidc.user_getfield("sub"))
    else:
        g.user = None

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

&lt;/div&gt;



&lt;p&gt;What we’re doing here is specifying settings for the Flask-OIDC library:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;OIDC_CLIENT_SECRETS&lt;/code&gt; setting tells Flask-OIDC where your OpenID Connect configuration file is located (the one you created in the previous section).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;OIDC_COOKIE_SECURE&lt;/code&gt; setting allows you to test out user login and registration in development without using SSL. If you were going to run your site publicly, you would remove this option and use SSL on your site.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;OIDC_CALLBACK_ROUTE&lt;/code&gt; setting tells Flask-OIDC what URL on your site will handle user login. This is a standard part of the OpenID Connect flows. This is out of scope for this article, but if you want to learn more, read our &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1"&gt;OpenID Connect primer&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;OIDC_SCOPES&lt;/code&gt; setting tells Flask-OIDC what data to request about the user when they log in. In this case, we’re requesting basic user information (email, name, etc.).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;SECRET_KEY&lt;/code&gt; setting should be set to a &lt;em&gt;long&lt;/em&gt;, random string. This is used to secure your Flask sessions (cookies) so that nobody can tamper with them. Make sure this variable stays private. It should never be publicly exposed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once that configuration data has been created, we also use a (currently) undefined &lt;code&gt;auth&lt;/code&gt; module (which we’ll get to in a moment) to initialize the Flask-OIDC library.&lt;/p&gt;

&lt;p&gt;We then register a Blueprint (which will be discussed in the next section).&lt;/p&gt;

&lt;p&gt;Finally, we define a special function called &lt;code&gt;before_request&lt;/code&gt;. This function will run automatically before each user request (hence the &lt;code&gt;@app.before_request&lt;/code&gt; decorator), and load up a user object is it is available.&lt;/p&gt;

&lt;p&gt;Here’s how this works.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once a user has logged in using OpenID Connect, they’ll have a session created and stored in a server-side cookie&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;if auth.oidc.user_loggedin&lt;/code&gt; code will check to see whether or not this cookie exists and is valid. If it is, then we’ll use the &lt;a href="https://github.com/okta/okta-sdk-python"&gt;okta Python library&lt;/a&gt; to retrieve the user’s account as a &lt;code&gt;User&lt;/code&gt; object that we can easily work with, and assign it to the special variable &lt;code&gt;g.user&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If no user is logged in, then &lt;code&gt;g.user&lt;/code&gt; will be set to &lt;code&gt;None&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The special &lt;code&gt;g.user&lt;/code&gt; value is something that we can use to store important data our application needs, like the current user, for example. This variable is available to us to use in templates, server-side code, etc. which makes it very handy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create User Login and Logout Views in Flask
&lt;/h3&gt;

&lt;p&gt;Create a new file, &lt;code&gt;blog/auth.py&lt;/code&gt; and paste in the following code. This file will hold all of our authentication related code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from os import environ

from flask import Blueprint, redirect, url_for
from flask_oidc import OpenIDConnect
from okta import UsersClient

bp = Blueprint("auth", __name__ , url_prefix="/")
oidc = OpenIDConnect()
okta_client = UsersClient("{{ OKTA_ORG_URL }}", "{{ OKTA_AUTH_TOKEN }}")

@bp.route("/login")
@oidc.require_login
def login():
    """
    Force the user to login, then redirect them to the dashboard.
    """
    return redirect(url_for("blog.dashboard"))

@bp.route("/logout")
def logout():
    """
    Log the user out of their account.
    """
    oidc.logout()
    return redirect(url_for("blog.index"))

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

&lt;/div&gt;



&lt;p&gt;Be sure to substitute &lt;code&gt;OKTA_ORG_URL&lt;/code&gt; and &lt;code&gt;OKTA_AUTH_TOKEN&lt;/code&gt; with the appropriate Okta values.&lt;/p&gt;

&lt;p&gt;What this file does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define a special &lt;code&gt;auth&lt;/code&gt; Blueprint. &lt;a href="http://flask.pocoo.org/docs/1.0/blueprints/"&gt;Blueprints in Flask&lt;/a&gt; are ways to modularize code to make it reusable in large systems. Each Blueprint has a name, a URL prefix (in this case that isn’t relevant, however), and it’s own mini application object.&lt;/li&gt;
&lt;li&gt;Define an &lt;code&gt;okta_client&lt;/code&gt; object. This allows us to talk to the Okta API to retrieve user data. While this isn’t strictly necessary, it allows us to more easily work with our users.&lt;/li&gt;
&lt;li&gt;Define a &lt;code&gt;login&lt;/code&gt; view to handle user login functionality. What these view functions do is this: when a user visits &lt;code&gt;/login&lt;/code&gt;, if the user is already logged in (via the &lt;code&gt;@oidc.require_login&lt;/code&gt; decorator), they’ll then be redirected to the dashboard page via the &lt;code&gt;redirect(...)&lt;/code&gt; function call. If the user isn’t logged in, the &lt;code&gt;@oidc.require_login&lt;/code&gt; decorator will redirect the user to the Okta authorization server and prompt them to either create a new account (user registration), or log into an existing account.&lt;/li&gt;
&lt;li&gt;Define a &lt;code&gt;logout&lt;/code&gt; view to handle logout functionality. If a user visits the &lt;code&gt;/logout&lt;/code&gt; URL, their session cookie will be deleted (via the &lt;code&gt;oidc.logout()&lt;/code&gt; call), and they’ll then be redirected to the homepage of the site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congratulations, you’ve now fully integrated user registration, login, and user management into your application! Not bad, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the Blog Views in Flask
&lt;/h2&gt;

&lt;p&gt;So far, we’ve built the front-end templates, created the database models, and wired up user authentication. The one thing we haven’t done, however, is define the core &lt;em&gt;behavior&lt;/em&gt; for our application: the views!&lt;/p&gt;

&lt;p&gt;In Flask, views are functions that run when a user visits a particular URL. If a user visits &lt;code&gt;/dashboard&lt;/code&gt;, for example, Flask needs to know what function to run and what to do to display the dashboard page to the user.&lt;/p&gt;

&lt;p&gt;Now that we’ve figured everything else out, let’s get the views built!&lt;/p&gt;

&lt;p&gt;First off, however, we need to update our app initialization code so our soon-to-be created blog views will work! Open &lt;code&gt;blog/ __init__.py&lt;/code&gt; and copy in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from os.path import dirname, join

from flask import Flask, g

from . import auth, blog, db

app = Flask( __name__ )
app.config.from_mapping(
    SECRET_KEY='LONG_RANDOM_STRING',
    OIDC_CLIENT_SECRETS=join(dirname(dirname( __file__ )), "client_secrets.json"),
    OIDC_COOKIE_SECURE=False,
    OIDC_CALLBACK_ROUTE="/oidc/callback",
    OIDC_SCOPES=["openid", "email", "profile"],
    OIDC_ID_TOKEN_COOKIE_NAME="oidc_token",
    SQLALCHEMY_DATABASE_URI="sqlite:///" + join(dirname(dirname( __file__ )), "database.sqlite"),
)

auth.oidc.init_app(app)
db.init_app(app)

app.register_blueprint(auth.bp)
app.register_blueprint(blog.bp)

@app.before_request
def before_request():
    """
    Load a user object into `g.user` before each request.
    """
    if auth.oidc.user_loggedin:
        g.user = auth.okta_client.get_user(auth.oidc.user_getfield("sub"))
    else:
        g.user = None

@app.errorhandler(404)
def page_not_found(e):
    """Render a 404 page."""
    return render_template("404.html"), 404

@app.errorhandler(403)
def insufficient_permissions(e):
    """Render a 403 page."""
    return render_template("403.html"), 403

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

&lt;/div&gt;



&lt;p&gt;We haven’t changed much here, except to import a &lt;code&gt;blog&lt;/code&gt; module and register it as a Blueprint. We’ve also defined two additional functions: one that will be run if a user visits a non-existent page (a 404), or if a user visits a page they don’t have permission to access (a 403).&lt;/p&gt;

&lt;p&gt;Next, create the file &lt;code&gt;blog/blog.py&lt;/code&gt; and paste in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Blueprint, abort, g, render_template, redirect, request, url_for
from slugify import slugify

from .auth import oidc, okta_client
from .db import Post, db

bp = Blueprint("blog", __name__ , url_prefix="/")

def get_posts(author_id):
    """
    Return all of the posts a given user created, ordered by date.
    """
    return Post.query.filter_by(author_id=author_id).order_by(Post.created.desc())

@bp.route("/")
def index():
    """
    Render the homepage.
    """
    posts = Post.query.order_by(Post.created.desc())
    posts_final = []

    for post in posts:
        u = okta_client.get_user(post.author_id)
        post.author_name = u.profile.firstName + " " + u.profile.lastName
        posts_final.append(post)

    return render_template("blog/index.html", posts=posts_final)

@bp.route("/dashboard", methods=["GET", "POST"])
@oidc.require_login
def dashboard():
    """
    Render the dashboard page.
    """
    if request.method == "GET":
        return render_template("blog/dashboard.html", posts=get_posts(g.user.id))

    post = Post(
        title=request.form.get("title"),
        body=request.form.get("body"),
        author_id = g.user.id,
        slug = slugify(request.form.get("title"))
    )

    db.session.add(post)
    db.session.commit()

    return render_template("blog/dashboard.html", posts=get_posts(g.user.id))

@bp.route("/&amp;lt;slug&amp;gt;")
def view_post(slug):
    """View a post."""
    post = Post.query.filter_by(slug=slug).first()
    if not post:
        abort(404)

    u = okta_client.get_user(post.author_id)
    post.author_name = u.profile.firstName + " " + u.profile.lastName

    return render_template("blog/post.html", post=post)

@bp.route("/&amp;lt;slug&amp;gt;/edit", methods=["GET", "POST"])
def edit_post(slug):
    """Edit a post."""
    post = Post.query.filter_by(slug=slug).first()

    if not post:
        abort(404)

    if post.author_id != g.user.id:
        abort(403)

    post.author_name = g.user.profile.firstName + " " + g.user.profile.lastName
    if request.method == "GET":
        return render_template("blog/edit.html", post=post)

    post.title = request.form.get("title")
    post.body = request.form.get("body")
    post.slug = slugify(request.form.get("title"))

    db.session.commit()
    return redirect(url_for(".view_post", slug=post.slug))

@bp.route("/&amp;lt;slug&amp;gt;/delete", methods=["POST"])
def delete_post(slug):
    """Delete a post."""
    post = Post.query.filter_by(slug=slug).first()

    if not post:
        abort(404)

    if post.author_id != g.user.id:
        abort(403)

    db.session.delete(post)
    db.session.commit()

    return redirect(url_for(".dashboard"))

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

&lt;/div&gt;



&lt;p&gt;I realize that’s a lot to take in, so let’s go through it one function at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The get_posts Helper Function
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_posts(author_id):
    """
    Return all of the posts a given user created, ordered by date.
    """
    return Post.query.filter_by(author_id=author_id).order_by(Post.created.desc())

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

&lt;/div&gt;



&lt;p&gt;This function is designed as a helper. What it does is query the database, looking for any posts written by a specific author, and returns them in descending order by date.&lt;/p&gt;

&lt;p&gt;This will be useful later when displaying the user dashboard page, as we’ll only want to show users blog posts &lt;em&gt;they’ve&lt;/em&gt; created on their dashboard page. This function allows us to easily get a list of those posts without duplicating code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The index View
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@bp.route("/")
def index():
    """
    Render the homepage.
    """
    posts = Post.query.order_by(Post.created.desc())
    posts_final = []

    for post in posts:
        u = okta_client.get_user(post.author_id)
        post.author_name = u.profile.firstName + " " + u.profile.lastName
        posts_final.append(post)

    return render_template("blog/index.html", posts=posts_final)

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

&lt;/div&gt;



&lt;p&gt;This view function is the homepage of the site. This function will run each time a user visits the &lt;code&gt;/&lt;/code&gt; URL. What it does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get a list of all blog posts on the site, ordered by date descending&lt;/li&gt;
&lt;li&gt;Loops through each post and extracts the author’s ID&lt;/li&gt;
&lt;li&gt;Uses the Okta Python library to retrieve the corresponding user’s first name and last name (this will allow us to display the author’s information to blog readers)&lt;/li&gt;
&lt;li&gt;Renders the &lt;code&gt;blog/index.html&lt;/code&gt; template we created much earlier, which displays a list of all blog posts, and who wrote them&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The dashboard View
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@bp.route("/dashboard", methods=["GET", "POST"])
@oidc.require_login
def dashboard():
    """
    Render the dashboard page.
    """
    if request.method == "GET":
        return render_template("blog/dashboard.html", posts=get_posts(g.user.id))

    post = Post(
        title=request.form.get("title"),
        body=request.form.get("body"),
        author_id = g.user.id,
        slug = slugify(request.form.get("title"))
    )

    db.session.add(post)
    db.session.commit()

    return render_template("blog/dashboard.html", posts=get_posts(g.user.id))

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

&lt;/div&gt;



&lt;p&gt;This view function is the user dashboard page. This function will run each time a user visits the &lt;code&gt;/dashboard&lt;/code&gt; URL. What it does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the user is viewing the dashboard, it just renders the &lt;code&gt;blog/dashboard.html&lt;/code&gt; template we defined earlier. This template shows the user a list of their previously created blog posts, and also allows the user to create new blog posts if they want by filling out a form.&lt;/li&gt;
&lt;li&gt;If the user is submitting a form (trying to create a new post), this view will create a new &lt;code&gt;Post&lt;/code&gt; object and save it to the database. Along the way, it will use the python-slugify library mentioned earlier to convert the title of the post into a URL-friendly format.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The view_post View
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@bp.route("/&amp;lt;slug&amp;gt;")
def view_post(slug):
    """View a post."""
    post = Post.query.filter_by(slug=slug).first()
    if not post:
        abort(404)

    u = okta_client.get_user(post.author_id)
    post.author_name = u.profile.firstName + " " + u.profile.lastName

    return render_template("blog/post.html", post=post)

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

&lt;/div&gt;



&lt;p&gt;This view function renders the post page. This function will run each time a user visits the &lt;code&gt;/&amp;lt;some-blog-slug-here&amp;gt;&lt;/code&gt; URL. What it does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look in the database for a blog post with the slug specified in the URL. If one can be found, it’ll render that page and show the blog to the user.&lt;/li&gt;
&lt;li&gt;If no matching blog post can be found, the user will see a 404 page and nothing more&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The edit_post View
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@bp.route("/&amp;lt;slug&amp;gt;/edit", methods=["GET", "POST"])
def edit_post(slug):
    """Edit a post."""
    post = Post.query.filter_by(slug=slug).first()

    if not post:
        abort(404)

    if post.author_id != g.user.id:
        abort(403)

    post.author_name = g.user.profile.firstName + " " + g.user.profile.lastName
    if request.method == "GET":
        return render_template("blog/edit.html", post=post)

    post.title = request.form.get("title")
    post.body = request.form.get("body")
    post.slug = slugify(request.form.get("title"))

    db.session.commit()
    return redirect(url_for(".view_post", slug=post.slug))

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

&lt;/div&gt;



&lt;p&gt;This view function allows users to edit a post. This function will run each time a user visits the &lt;code&gt;/&amp;lt;some-blog-slug-here&amp;gt;/edit&lt;/code&gt; URL. What it does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look in the database for a blog post with the slug specified in the URL. If one can be found, it’ll update the post accordingly (assuming the user has the correct permissions). If the user doesn’t have the correct permissions, they’ll be shown a 403 page.&lt;/li&gt;
&lt;li&gt;If no matching blog post can be found, the user will see a 404 page and nothing more&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The delete_post View
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@bp.route("/&amp;lt;slug&amp;gt;/delete", methods=["POST"])
def delete_post(slug):
    """Delete a post."""
    post = Post.query.filter_by(slug=slug).first()

    if not post:
        abort(404)

    if post.author_id != g.user.id:
        abort(403)

    db.session.delete(post)
    db.session.commit()

    return redirect(url_for(".dashboard"))

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

&lt;/div&gt;



&lt;p&gt;This view function allows users to delete a post. This function will run each time a user visits the &lt;code&gt;/&amp;lt;some-blog-slug-here&amp;gt;/delete&lt;/code&gt; URL. What it does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look in the database for a blog post with the slug specified in the URL. If one can be found, it’ll delete the post from the database (assuming the user has the correct permissions). If the user doesn’t have the correct permissions, they’ll be shown a 403 page.&lt;/li&gt;
&lt;li&gt;If no matching blog post can be found, the user will see a 404 page and nothing more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And… That’s it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Your New Flask + Python App
&lt;/h2&gt;

&lt;p&gt;Now that your app is fully built, go test it out! Open up &lt;code&gt;http://localhost:5000&lt;/code&gt;, create an account, log in, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NyntUJ2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/app-usage-738749b9ea16985d42493459c6ebc0421da61c19700a0a99f1f9608c50ec63d2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NyntUJ2i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://developer.okta.com/assets/blog/build-a-simple-crud-app-with-python-and-flask/app-usage-738749b9ea16985d42493459c6ebc0421da61c19700a0a99f1f9608c50ec63d2.gif" alt="app usage" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, building a Flask app with user registration, login, databases, templates, etc. doesn’t have to be hard!&lt;/p&gt;

&lt;p&gt;If you’re interested in learning more about web authentication and security, you may also want to check out some of &lt;a href="https://developer.okta.com/blog/"&gt;our other articles&lt;/a&gt;, or &lt;a href="https://twitter.com/oktadev"&gt;follow us&lt;/a&gt; on Twitter — we write a lot about interesting web development topics.&lt;/p&gt;

&lt;p&gt;Here are three of my favorites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/07/12/flask-tutorial-simple-user-registration-and-login"&gt;Flask Tutorial: Simple User Registration and Login&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/06/08/add-authentication-to-any-web-page-in-10-minutes"&gt;Add Authentication to Any Web Page in 10 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/06/20/what-happens-if-your-jwt-is-stolen"&gt;What Happens if Your JWT is Stolen?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flask</category>
      <category>python</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Flask Tutorial: Simple User Registration and Login</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Thu, 12 Jul 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/flask-tutorial-simple-user-registration-and-login-23kk</link>
      <guid>https://dev.to/oktadev/flask-tutorial-simple-user-registration-and-login-23kk</guid>
      <description>&lt;p&gt;Flask is my favorite Python web framework. It’s minimal, it’s fast, and most of all: &lt;em&gt;it’s fun&lt;/em&gt;. I love almost everything about Flask development, with one exception: user management.&lt;/p&gt;

&lt;p&gt;User management in Flask, just like in many other web frameworks, is difficult. I can’t tell you how many times I’ve created user databases, set up groups and roles, integrated social login providers, handled password reset workflows, configured multi-factor authentication workflows, etc. Even awesome libraries like &lt;a href="http://flask-login.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Flask-Login&lt;/a&gt; and &lt;a href="https://pythonhosted.org/Flask-Security/" rel="noopener noreferrer"&gt;Flask-Security&lt;/a&gt; can be difficult to setup and maintain over long periods of time as your requirements change.&lt;/p&gt;

&lt;p&gt;In this short tutorial, I’ll show you what I think is one of the best and simplest ways to manage users for your Flask web applications: OpenID Connect. If you haven’t heard of it, &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt; is an open protocol that makes managing user authentication and authorization simple.&lt;/p&gt;

&lt;p&gt;Follow along below and you’ll learn how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a simple Flask website&lt;/li&gt;
&lt;li&gt;Use OpenID Connect for user authentication and authorization&lt;/li&gt;
&lt;li&gt;Use Okta as your authorization server to store and manage your user accounts in a simple, straightforward way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’d like to skip the tutorial and just check out the fully built project, you can go &lt;a href="https://github.com/rdegges/okta-flask-example" rel="noopener noreferrer"&gt;view it on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize Authentication for Your Flask App with Okta
&lt;/h2&gt;

&lt;p&gt;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 OpenID Connect to make integration seamless.&lt;/p&gt;

&lt;p&gt;In this tutorial, you’ll use Okta to store the user accounts for your web app, and you’ll use OpenID Connect to talk to Okta to handle the logistics around authentication and authorization.&lt;/p&gt;

&lt;p&gt;To get started, you first need to go create a free Okta developer account: &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;https://developer.okta.com/signup/&lt;/a&gt;. Once you’ve created your account and logged in, follow the steps below configure Okta and then you’ll be ready to write some 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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-registration-page-ee14e7516bdc7df3e6e950a2c385706754c5300d842a1374785fd9e43cab2a6b.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-registration-page-ee14e7516bdc7df3e6e950a2c385706754c5300d842a1374785fd9e43cab2a6b.png" alt="Okta registration page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Store Your Org URL
&lt;/h3&gt;

&lt;p&gt;The first thing you need to do is copy down the &lt;strong&gt;Org URL&lt;/strong&gt; from the top-right portion of your Okta dashboard page. This URL will be used to route to your authorization server, communicate with it, and much more. You’ll need this value later, so don’t forget it.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-org-url-b26a98af3fa71a8f88519b5154d16d10fae846ff3df95d09995fcd61fa2c6175.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-org-url-b26a98af3fa71a8f88519b5154d16d10fae846ff3df95d09995fcd61fa2c6175.png" alt="Okta org URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create an OpenID Connect Application
&lt;/h3&gt;

&lt;p&gt;Okta allows you to store and manage users for multiple applications you might be creating. This means that before we can go any further, you need to create a new OpenID Connect application for this project.&lt;/p&gt;

&lt;p&gt;Applications in OpenID Connect have a username and password (referred to as a client ID and client secret) that allow your authorization server to recognize which application is talking to it at any given time.&lt;/p&gt;

&lt;p&gt;To create a new application browse to the &lt;strong&gt;Applications&lt;/strong&gt; tab 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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-application-page-5d3d0ee99d0d6888f30bffc5fa3d58ddaafe907dfd2ec315589435b2fc7bb23b.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-application-page-5d3d0ee99d0d6888f30bffc5fa3d58ddaafe907dfd2ec315589435b2fc7bb23b.png" alt="Okta application page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click the &lt;strong&gt;Web&lt;/strong&gt; platform option (since this project is a web app).&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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-create-application-page-681dcd71ac7de879a92e80d243020f9c9be6edc17e6ae0b0adb40a70936eac24.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-create-application-page-681dcd71ac7de879a92e80d243020f9c9be6edc17e6ae0b0adb40a70936eac24.png" alt="Okta create application page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the settings page, enter the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; : Simple Flask App&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:5000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login redirect URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:5000/oidc/callback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can leave all the other values unchanged.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-create-application-settings-page-6113616138c4f65e25532ad8013ed3359a8e389b08f8f093acb25c8ca43f9091.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-create-application-settings-page-6113616138c4f65e25532ad8013ed3359a8e389b08f8f093acb25c8ca43f9091.png" alt="Okta create application settings page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that your application has been created, copy down the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client secret&lt;/strong&gt; values on the following page, you’ll need them later when we start writing 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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-application-credentials-page-2f5b916ff40dc7425e731c801f9b087342846ed828a7979ab79127059d67d6b3.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-application-credentials-page-2f5b916ff40dc7425e731c801f9b087342846ed828a7979ab79127059d67d6b3.png" alt="Okta application credentials page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create an Authentication Token
&lt;/h3&gt;

&lt;p&gt;In order to access the Okta APIs and be able to manage your user accounts with a great deal of granularity, you’ll also need to create an Okta authentication token. This is an API key that will be used later on communicate with the Okta APIs and allows you to do things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create, update, and delete users&lt;/li&gt;
&lt;li&gt;Create, update, and delete groups&lt;/li&gt;
&lt;li&gt;Manage application settings&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create an authentication token click the &lt;strong&gt;API&lt;/strong&gt; tab at the top of the page followed by the &lt;strong&gt;Create Token&lt;/strong&gt; button. Give your token a name, preferably the same name as your application, then click &lt;strong&gt;Create Token&lt;/strong&gt;. Once your token has been created, copy down the token value as you will need it 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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-create-token-page-008a4364f7541ac93b9baf5d3b381ba889bd7188fd6101b19901f0cdf9821a6c.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-create-token-page-008a4364f7541ac93b9baf5d3b381ba889bd7188fd6101b19901f0cdf9821a6c.png" alt="Okta create token page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Enable User Registration
&lt;/h3&gt;

&lt;p&gt;The last piece of setup you need to complete is to enable user registration functionality for the authorization server. Normally, authorization servers only support login, logout, and stuff like that. But Okta’s authorization server also supports self-service registration, so that users can create accounts, log into them, reset passwords, and basically do everything without you writing any code for it.&lt;/p&gt;

&lt;p&gt;In your Okta dashboard, you’ll notice a small button labeled &lt;strong&gt;&amp;lt; &amp;gt; Developer Console&lt;/strong&gt; at the top-left of your page. Hover over that button and select the &lt;strong&gt;Classic UI&lt;/strong&gt; menu option that appears.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-classic-ui-dropdown-249d1b924c3db38af5d62bf17be65a32579117d9d23c8c28cb7e365eba7d8f85.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-classic-ui-dropdown-249d1b924c3db38af5d62bf17be65a32579117d9d23c8c28cb7e365eba7d8f85.png" alt="Okta classic UI dropdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, hover over the &lt;strong&gt;Directory&lt;/strong&gt; tab at the top of the page then select the &lt;strong&gt;Self-Service Registration&lt;/strong&gt; menu item. On this page click the &lt;strong&gt;Enable Registration&lt;/strong&gt; button.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-enable-self-service-registration-page-2cfef05884c196fa53bc7c55728c77437713fffa5d549e1874e18c2593825b1f.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-enable-self-service-registration-page-2cfef05884c196fa53bc7c55728c77437713fffa5d549e1874e18c2593825b1f.png" alt="Okta enable self-service registration page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the configuration page, leave all the settings as their default values, except for two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disable the &lt;strong&gt;User must verify email address to be activated.&lt;/strong&gt; checkbox. This setting removes the requirement for new users to verify their email address before being allowed to access your web app.&lt;/li&gt;
&lt;li&gt;Set the &lt;strong&gt;Default redirect&lt;/strong&gt; option by clicking the &lt;strong&gt;Custom URL&lt;/strong&gt; radio box and entering &lt;code&gt;http://localhost:5000/dashboard&lt;/code&gt; as the value. This setting tells the authorization server where to redirect users after they’ve successfully created a new account on your site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve clicked &lt;strong&gt;Save&lt;/strong&gt; , the last thing you need to is switch back to the developer console.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-self-service-registration-settings-page-5b1f7922a1342ce35f0f876587e479660d0f51f6fa59d69b239a6d965da8dbf7.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%2Fflask-tutorial-simple-user-registration-and-login%2Fokta-self-service-registration-settings-page-5b1f7922a1342ce35f0f876587e479660d0f51f6fa59d69b239a6d965da8dbf7.png" alt="Okta self-service registration settings page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hover over the &lt;strong&gt;Classic UI&lt;/strong&gt; button at the top right of the page and select the &lt;strong&gt;&amp;lt; &amp;gt; Developer Console&lt;/strong&gt; menu item from the drop-down.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Python and Flask Dependencies
&lt;/h2&gt;

&lt;p&gt;The first thing you need to do in order to initialize your Flask app is install all of the required dependencies. If you don’t have Python installed on your computer already, please go &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;install it now&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : I also strongly recommend you get familiar with &lt;a href="https://docs.pipenv.org/" rel="noopener noreferrer"&gt;pipenv&lt;/a&gt; when you get some time. It’s a great tool that makes managing Python dependencies very simple.&lt;/p&gt;

&lt;p&gt;Now install the dependencies required for this application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install Flask&amp;gt;=1.0.0
pip install flask-oidc&amp;gt;=1.4.0
pip install okta==0.0.4

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialize Your Flask App
&lt;/h2&gt;

&lt;p&gt;Now that the dependencies are installed, let’s start by creating a simple Flask app. We’ll build on this simple “hello, world!” app until we’ve got all our functionality included.&lt;/p&gt;

&lt;p&gt;Create an &lt;code&gt;app.py&lt;/code&gt; file and enter the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask

app = Flask( __name__ )

@app.route('/')
def index():
    return 'hello, world!'

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

&lt;/div&gt;



&lt;p&gt;Open the terminal and run the following code to start up your new Flask app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FLASK_APP=app.py flask run

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

&lt;/div&gt;



&lt;p&gt;Once your Flask app is running, go visit &lt;code&gt;http://localhost:5000&lt;/code&gt; in the browser to see the hello world message!&lt;/p&gt;

&lt;p&gt;As you can see from the small file above, building a minimalist app with Flask can be really simple. All you need to do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import the Flask library&lt;/li&gt;
&lt;li&gt;Create a Flask app object&lt;/li&gt;
&lt;li&gt;Define a function (called a view) that runs when a particular URL is requested by a user (in this case, the &lt;code&gt;/&lt;/code&gt; URL)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not bad, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an Index and Dashboard View in Flask
&lt;/h2&gt;

&lt;p&gt;The next step to building a simple Flask app is creating a homepage and dashboard page. The homepage is what will be shown to the user when they visit the &lt;code&gt;/&lt;/code&gt; URL, and the dashboard page (&lt;code&gt;/dashboard&lt;/code&gt;) will be shown to the user once they’ve logged into their account.&lt;/p&gt;

&lt;p&gt;When I’m building web apps, I like to define my templates and views first so I can get the hard part out of the way (design isn’t my strong suit).&lt;/p&gt;

&lt;p&gt;To get started, open up you &lt;code&gt;app.py&lt;/code&gt; file from before and modify it to look like 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;from flask import Flask, render_template

app = Flask( __name__ )

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/dashboard")
def dashboard():
    return render_template("dashboard.html")

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

&lt;/div&gt;



&lt;p&gt;You’ll notice that you now have two view functions defined: &lt;code&gt;index&lt;/code&gt; (which renders the homepage) and &lt;code&gt;dashboard&lt;/code&gt; (which renders the dashboard page). Both of the view functions are calling the &lt;code&gt;render_template&lt;/code&gt; Flask function, which is responsible for displaying an HTML page to the user.&lt;/p&gt;

&lt;p&gt;Now, you obviously haven’t created those HTML templates yet, so let’s do that next!&lt;/p&gt;

&lt;p&gt;Templates in Flask are built using the &lt;a href="http://jinja.pocoo.org/docs/2.10/" rel="noopener noreferrer"&gt;Jinja2 templating language&lt;/a&gt;. If you’re familiar with HTML, it should look natural.&lt;/p&gt;

&lt;p&gt;Let’s start by creating the template files we’ll need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir templates
touch templates/{layout.html,index.html,dashboard.html}

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

&lt;/div&gt;



&lt;p&gt;All templates in Flask should live inside the &lt;code&gt;templates&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Next, open up the &lt;code&gt;templates/layout.html&lt;/code&gt; file and enter the following code.&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;!doctype html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"&amp;gt;
    &amp;lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous"&amp;gt;
    &amp;lt;link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"&amp;gt;
    &amp;lt;title&amp;gt;Simple Flask App | {% block title %}{% endblock %}&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom box-shadow"&amp;gt;
      &amp;lt;h5 class="my-0 mr-md-auto font-weight-normal"&amp;gt;Simple Flask App&amp;lt;/h5&amp;gt;
      &amp;lt;nav class="my-2 my-md-0 mr-md-3"&amp;gt;
        &amp;lt;a class="p-2 text-dark" href="/" title="Home"&amp;gt;Home&amp;lt;/a&amp;gt;
        {% if not g.user %}
          &amp;lt;a class="p-2 text-dark" href="/login"&amp;gt;Log In / Register&amp;lt;/a&amp;gt;
        {% else %}
          &amp;lt;a class="p-2 text-dark" href="/dashboard"&amp;gt;Dashboard&amp;lt;/a&amp;gt;
          &amp;lt;a class="p-2 text-dark" href="/logout"&amp;gt;Logout&amp;lt;/a&amp;gt;
        {% endif %}
      &amp;lt;/nav&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="container"&amp;gt;
      {% block body %}{% endblock %}
    &amp;lt;/div&amp;gt;
    &amp;lt;footer class="text-center"&amp;gt;Created by &amp;lt;a href="https://twitter.com/rdegges"&amp;gt;@rdegges&amp;lt;/a&amp;gt;, built using &amp;lt;a href="https://twitter.com/okta"&amp;gt;@okta&amp;lt;/a&amp;gt;.
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;layout.html&lt;/code&gt; file is our &lt;em&gt;base&lt;/em&gt; template. It’s basically a building block that all the other templates will inherit from. By defining our common, &lt;em&gt;shared&lt;/em&gt; HTML in this file, we can avoid writing redundant HTML everywhere else. Yey!&lt;/p&gt;

&lt;p&gt;Now, this file contains all the basic stuff you might expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A simple, &lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt;-based layout&lt;/li&gt;
&lt;li&gt;A nav bar (that contains some special Jinja2 logic)&lt;/li&gt;
&lt;li&gt;A special Jinja2 body&lt;/li&gt;
&lt;li&gt;A footer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a look at one interesting part of the template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% if not g.user %}
  &amp;lt;a class="p-2 text-dark" href="/login"&amp;gt;Log In / Register&amp;lt;/a&amp;gt;
{% else %}
  &amp;lt;a class="p-2 text-dark" href="/dashboard"&amp;gt;Dashboard&amp;lt;/a&amp;gt;
  &amp;lt;a class="p-2 text-dark" href="/logout"&amp;gt;Logout&amp;lt;/a&amp;gt;
{% endif %}

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

&lt;/div&gt;



&lt;p&gt;Anything in a Jinja2 tag (the &lt;code&gt;{% … %}&lt;/code&gt; stuff) will be compiled by Flask before being shown to the user. In the example above, we’re basically telling Flask that if the object &lt;code&gt;g.user&lt;/code&gt; exists, we should render a dashboard and logout link in the navbar, but if no &lt;code&gt;g.user&lt;/code&gt; object exists, we should show a login button instead.&lt;/p&gt;

&lt;p&gt;We’re doing this because eventually we’re going to have the user’s account accessible via the &lt;code&gt;g.user&lt;/code&gt; object and we want the navbar to be smart in regards to what the user sees.&lt;/p&gt;

&lt;p&gt;The next interesting part of the template is the body tag:&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;div class="container"&amp;gt;
  {% block body %}{% endblock %}
&amp;lt;/div&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;block&lt;/code&gt; Jinja2 tag allows us to inject content from a child template into this parent template. This is what lets us build complex HTML pages without writing redundant code.&lt;/p&gt;

&lt;p&gt;Now that the layout is defined, let’s create the homepage. Open the &lt;code&gt;templates/index.html&lt;/code&gt; file and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}Home{% endblock %}

{% block body %}
  &amp;lt;h1 class="text-center"&amp;gt;Simple Flask App&amp;lt;/h1&amp;gt;
  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="col-sm-6 offset-sm-3"&amp;gt;
      &amp;lt;div class="jumbotron"&amp;gt;
        Welcome to this simple Flask example app. It shows you how to easily
        enable users to register, login, and logout of a Flask web app using &amp;lt;a
           href="https://developer.okta.com"&amp;gt;Okta&amp;lt;/a&amp;gt;.
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{% extends "layout.html" %}&lt;/code&gt; tag is what tells the template engine that this template depends on the &lt;code&gt;layout.html&lt;/code&gt; template to work.&lt;/p&gt;

&lt;p&gt;Everything inside the &lt;code&gt;block&lt;/code&gt; tags is then injected back into the parent template from before. By combining these two things together, you’re now able to have a fully rendered homepage!&lt;/p&gt;

&lt;p&gt;Next, go ahead and place the following code into the &lt;code&gt;templates/dashboard.html&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{% extends "layout.html" %}

{% block title %}Dashboard{% endblock %}

{% block body %}
  &amp;lt;h1 class="text-center"&amp;gt;Dashboard&amp;lt;/h1&amp;gt;
  &amp;lt;div class="row"&amp;gt;
    &amp;lt;div class="col-sm-8 offset-sm-2"&amp;gt;
      &amp;lt;p&amp;gt;Welcome to the dashboard, {{ g.user.profile.firstName }}!&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;Your user information has been pulled from the &amp;lt;code&amp;gt;g.user&amp;lt;/code&amp;gt;
      object, which makes accessing your user information simple. Your first
      name, for example, is available via the &amp;lt;code&amp;gt;g.user.profile.firstName&amp;lt;/code&amp;gt;
      property. Your user id (&amp;lt;code&amp;gt;{{ g.user.id }}&amp;lt;/code&amp;gt;), is pulled from the &amp;lt;code&amp;gt;g.user.id&amp;lt;/code&amp;gt; property!&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
{% endblock %}

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

&lt;/div&gt;



&lt;p&gt;This template works in the same way, except it also outputs some variables. For instance, the &lt;code&gt;{{ g.user.id }}&lt;/code&gt; value will output that ID value into the HTML template directly. These variables will eventually be available once we hook up the OpenID Connect library.&lt;/p&gt;

&lt;p&gt;The last thing you need to do before testing things is add a bit of CSS to make things look nicer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir static
touch static/style.css

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

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;static/style.css&lt;/code&gt; and copy in the following CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;h1 {
  margin: 1em 0;
}

footer {
  padding-top: 2em;
}

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

&lt;/div&gt;



&lt;p&gt;Finally, now that your templates have been created, go test them out!&lt;/p&gt;

&lt;p&gt;Visit &lt;code&gt;http://localhost:5000&lt;/code&gt; and you should see your beautiful new website.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fapp-homepage-22521e4e865fb034c4c49a14143bb699c5f4c467f8d08fcd077d16e4464c8942.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%2Fflask-tutorial-simple-user-registration-and-login%2Fapp-homepage-22521e4e865fb034c4c49a14143bb699c5f4c467f8d08fcd077d16e4464c8942.png" alt="app homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add User Registration and Login to Your Flask App
&lt;/h2&gt;

&lt;p&gt;Now that the UI for the app is finished, let’s get the interesting stuff working: user registration and login.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an OpenID Connect Config File
&lt;/h3&gt;

&lt;p&gt;Create a new file named &lt;code&gt;client_secrets.json&lt;/code&gt; in the root of your project folder and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "web": {
    "client_id": "{{ OKTA_CLIENT_ID }}",
    "client_secret": "{{ OKTA_CLIENT_SECRET }}",
    "auth_uri": "{{ OKTA_ORG_URL }}/oauth2/default/v1/authorize",
    "token_uri": "{{ OKTA_ORG_URL }}/oauth2/default/v1/token",
    "issuer": "{{ OKTA_ORG_URL }}/oauth2/default",
    "userinfo_uri": "{{ OKTA_ORG_URL }}/oauth2/default/userinfo",
    "redirect_uris": [
      "http://localhost:5000/oidc/callback"
    ]
  }
}

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

&lt;/div&gt;



&lt;p&gt;Be sure to replace the placeholder variables with your actual Okta information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;{{ OKTA_ORG_URL }}&lt;/code&gt; with the Org URL on your dashboard page&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;{{ OKTA_CLIENT_ID }}}&lt;/code&gt; with the Client ID on your application page&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;{{ OKTA_CLIENT_SECRET }}&lt;/code&gt; with the Client secret on your application page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This file will be used by the Flask-OIDC library which we’ll be configuring in a moment. These settings essentially tell the OpenID Connect library what OpenID Connect application you’re using to authenticate against, and what your authorization server API endpoints are.&lt;/p&gt;

&lt;p&gt;The URIs above simply point to your newly created Okta resources so that the Flask library will be able to talk to it properly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Flask-OIDC
&lt;/h3&gt;

&lt;p&gt;Open up &lt;code&gt;app.py&lt;/code&gt; and paste in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, render_template
from flask_oidc import OpenIDConnect

app = Flask( __name__ )
app.config["OIDC_CLIENT_SECRETS"] = "client_secrets.json"
app.config["OIDC_COOKIE_SECURE"] = False
app.config["OIDC_CALLBACK_ROUTE"] = "/oidc/callback"
app.config["OIDC_SCOPES"] = ["openid", "email", "profile"]
app.config["SECRET_KEY"] = "{{ LONG_RANDOM_STRING }}"
oidc = OpenIDConnect(app)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/dashboard")
def dashboard():
    return render_template("dashboard.html")

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

&lt;/div&gt;



&lt;p&gt;What we’re doing here is configuring the Flask-OIDC library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;OIDC_CLIENT_SECRETS&lt;/code&gt; setting tells Flask-OIDC where your OpenID Connect configuration file is located (the one you created in the previous section).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;OIDC_COOKIE_SECURE&lt;/code&gt; setting allows you to test out user login and registration in development without using SSL. If you were going to run your site publicly, you would remove this option and use SSL on your site.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;OIDC_CALLBACK_ROUTE&lt;/code&gt; setting tells Flask-OIDC what URL on your site will handle user login. This is a standard part of the OpenID Connect flows. This is out of scope for this article, but if you want to learn more, go read our &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;OpenID Connect primer&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;OIDC_SCOPES&lt;/code&gt; setting tells Flask-OIDC what data to request about the user when they log in. In this case, we’re requesting basic user information (email, name, etc.).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;SECRET_KEY&lt;/code&gt; setting should be set to a &lt;em&gt;long&lt;/em&gt;, random string. This is used to secure your Flask sessions (cookies) so that nobody can tamper with them. Make sure this variable stays private. It should never be publicly exposed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, after all the configuration is finished, we initialize the Flask-OIDC extension by creating the &lt;code&gt;oidc&lt;/code&gt; object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Inject the User Into Each Request
&lt;/h3&gt;

&lt;p&gt;Open up &lt;code&gt;app.py&lt;/code&gt; and paste in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, render_template, g
from flask_oidc import OpenIDConnect
from okta import UsersClient

app = Flask( __name__ )
app.config["OIDC_CLIENT_SECRETS"] = "client_secrets.json"
app.config["OIDC_COOKIE_SECURE"] = False
app.config["OIDC_CALLBACK_ROUTE"] = "/oidc/callback"
app.config["OIDC_SCOPES"] = ["openid", "email", "profile"]
app.config["SECRET_KEY"] = "{{ LONG_RANDOM_STRING }}"
app.config["OIDC_ID_TOKEN_COOKIE_NAME"] = "oidc_token"
oidc = OpenIDConnect(app)
okta_client = UsersClient("{{ OKTA_ORG_URL }}", "{{ OKTA_AUTH_TOKEN }}")

@app.before_request
def before_request():
    if oidc.user_loggedin:
        g.user = okta_client.get_user(oidc.user_getfield("sub"))
    else:
        g.user = None

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/dashboard")
def dashboard():
    return render_template("dashboard.html")

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

&lt;/div&gt;



&lt;p&gt;What we’re doing here is importing the &lt;code&gt;okta&lt;/code&gt; Python library, and using it to define the &lt;code&gt;okta_client&lt;/code&gt; object. This client object will be used to retrieve a robust User object that you can use to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the currently logged in user&lt;/li&gt;
&lt;li&gt;Make changes to the user’s account&lt;/li&gt;
&lt;li&gt;Store and retrieve user information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make sure you replace &lt;code&gt;{{ OKTA_ORG_URL }}&lt;/code&gt; and &lt;code&gt;{{ OKTA_AUTH_TOKEN }}&lt;/code&gt; with the values you wrote down in the first section of this tutorial. These two variables are mandatory so the &lt;code&gt;okta&lt;/code&gt; library can communicate with the Okta API service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.before_request
def before_request():
    if oidc.user_loggedin:
        g.user = okta_client.get_user(oidc.user_getfield("sub"))
    else:
        g.user = None

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

&lt;/div&gt;



&lt;p&gt;The code above is where the magic happens. This function will be executed each time a user makes a request to view a page on the site before the normal view code runs. What this function does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check to see whether or not a user is logged in via OpenID Connect or not (the &lt;code&gt;oidc.user_loggedin&lt;/code&gt; value is provided by the Flask-OIDC library)&lt;/li&gt;
&lt;li&gt;If a user is logged in, it will grab the user’s unique user ID from the user’s session, then use that ID to fetch the user object from the Okta API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all cases, there will be a newly created value: &lt;code&gt;g.user&lt;/code&gt;. In Flask, you can store request data on the &lt;code&gt;g&lt;/code&gt; object, which can be accessed from anywhere: view code, templates, etc. This makes it a convenient place to store something like a user object so it can easily be used later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Enable User Registration, Login, and Logout
&lt;/h3&gt;

&lt;p&gt;Open up &lt;code&gt;app.py&lt;/code&gt; and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, render_template, g, redirect, url_for
from flask_oidc import OpenIDConnect
from okta import UsersClient

app = Flask( __name__ )
app.config["OIDC_CLIENT_SECRETS"] = "client_secrets.json"
app.config["OIDC_COOKIE_SECURE"] = False
app.config["OIDC_CALLBACK_ROUTE"] = "/oidc/callback"
app.config["OIDC_SCOPES"] = ["openid", "email", "profile"]
app.config["SECRET_KEY"] = "{{ LONG_RANDOM_STRING }}"
app.config["OIDC_ID_TOKEN_COOKIE_NAME"] = "oidc_token"
oidc = OpenIDConnect(app)
okta_client = UsersClient("{{ OKTA_ORG_URL }}", "{{ OKTA_AUTH_TOKEN }}")

@app.before_request
def before_request():
    if oidc.user_loggedin:
        g.user = okta_client.get_user(oidc.user_getfield("sub"))
    else:
        g.user = None

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/dashboard")
@oidc.require_login
def dashboard():
    return render_template("dashboard.html")

@app.route("/login")
@oidc.require_login
def login():
    return redirect(url_for(".dashboard"))

@app.route("/logout")
def logout():
    oidc.logout()
    return redirect(url_for(".index"))

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

&lt;/div&gt;



&lt;p&gt;There are only a few things different here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You now have a &lt;code&gt;login&lt;/code&gt; view. The view will redirect the user to Okta (the OpenID Connect provider) to register or login. This is powered by the &lt;code&gt;@oidc.require_login&lt;/code&gt; decorator which is provided by the Flask-OIDC library. Once the user has been logged in, they’ll be redirected to the dashboard page.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;logout&lt;/code&gt; view is also present. This simply logs the user out using the &lt;code&gt;oidc.logout()&lt;/code&gt; method and then redirects the user to the homepage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And with that, your application is now fully functional!&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Your New Flask App
&lt;/h2&gt;

&lt;p&gt;Now that your app is fully built, go test it out! Open up &lt;code&gt;http://localhost:5000&lt;/code&gt;, create an account, log in, etc.&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%2Fflask-tutorial-simple-user-registration-and-login%2Fapp-usage-6f982cf53a06b2aa89c0981a861631ab066e0e474f9342b6161e8b06be4bd7d0.gif" 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%2Fflask-tutorial-simple-user-registration-and-login%2Fapp-usage-6f982cf53a06b2aa89c0981a861631ab066e0e474f9342b6161e8b06be4bd7d0.gif" alt="app usage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, building a Flask app with user registration, login, etc. doesn’t have to be hard!&lt;/p&gt;

&lt;p&gt;If you’re interested in learning more about web authentication and security, you may also want to check out some of &lt;a href="https://developer.okta.com/blog/" rel="noopener noreferrer"&gt;our other articles&lt;/a&gt;, or &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;follow us&lt;/a&gt; on Twitter — we write a lot about interesting web development topics.&lt;/p&gt;

&lt;p&gt;Here are two of my favorites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/06/08/add-authentication-to-any-web-page-in-10-minutes" rel="noopener noreferrer"&gt;Add Authentication to Any Web Page in 10 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/06/20/what-happens-if-your-jwt-is-stolen" rel="noopener noreferrer"&gt;What Happens if Your JWT is Stolen?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>flask</category>
      <category>beginners</category>
      <category>security</category>
    </item>
    <item>
      <title>Tutorial: Build a Basic CRUD App with Node.js</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Thu, 28 Jun 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/tutorial-build-a-basic-crud-app-with-nodejs-1ohn</link>
      <guid>https://dev.to/oktadev/tutorial-build-a-basic-crud-app-with-nodejs-1ohn</guid>
      <description>&lt;p&gt;Node.js is eating the world. Many of the largest companies are building more and more of their websites and API services with Node.js, and there’s no sign of a slowdown. I’ve been working with Node.js since 2012 and have been excited to see the community and tooling grow and evolve — there’s no better time to get started with Node.js development than right now.&lt;/p&gt;

&lt;p&gt;This tutorial will take you step-by-step through building a fully functional Node.js website. Along the way you’ll learn about Express.js, the most popular web framework, user authentication with &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;OpenID Connect&lt;/a&gt;, locking down routes to enforce login restrictions, and performing CRUD operations with a database (creating, reading, updating, and deleting data). This tutorial uses the following technologies but doesn’t require any prior experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express.js&lt;/a&gt; and &lt;a href="https://pugjs.org/api/getting-started.html" rel="noopener noreferrer"&gt;Pug&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Okta’s &lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/oidc-middleware" rel="noopener noreferrer"&gt;OIDC-middleware&lt;/a&gt; and &lt;a href="https://github.com/okta/okta-sdk-nodejs" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://docs.sequelizejs.com/" rel="noopener noreferrer"&gt;Sequelize.js&lt;/a&gt;, a popular ORM for working with databases in Node.js&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’d like to skip the tutorial and just check out the fully built project, you can go &lt;a href="https://github.com/rdegges/okta-express-blog" rel="noopener noreferrer"&gt;view it on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  About Express.js
&lt;/h2&gt;

&lt;p&gt;Express.js is the most popular web framework in the Node.js ecosystem. It’s incredibly simple and minimalistic. Furthermore, there are thousands of developer libraries that work with Express, making developing with it fun and flexible.&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fexpress-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fexpress-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3.png" alt="express website screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Regardless of whether you’re trying to build a website or an API, Express.js provides tons of features and a nice developer experience.&lt;/p&gt;

&lt;p&gt;Through this tutorial, you’ll be building a simple blog. The blog you build will have a homepage that lists the most recent posts, a login page where users can authenticate, a dashboard page where users can create and edit posts, and logout functionality.&lt;/p&gt;

&lt;p&gt;The blog will be built using Express.js, the user interface will be built using Pug, the authentication component will be handled by &lt;a href="https://developer.okta.com/" rel="noopener noreferrer"&gt;Okta&lt;/a&gt;, and the blog post storage and database management will be handled by Sequelize.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Your Express.js App
&lt;/h2&gt;

&lt;p&gt;Before we begin, make sure you have a recent version of Node.js installed. If you don’t already have Node.js installed, please &lt;a href="https://nodejs.org/en/download/package-manager/" rel="noopener noreferrer"&gt;visit this page&lt;/a&gt; and install it for your operating system before continuing.&lt;/p&gt;

&lt;p&gt;To get your project started quickly you can leverage &lt;a href="https://github.com/expressjs/generator" rel="noopener noreferrer"&gt;express-generator&lt;/a&gt;. This is an officially maintained program that allows you to easily scaffold an Express.js website with minimal effort.&lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;express-generator&lt;/code&gt; run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g express-generator

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

&lt;/div&gt;



&lt;p&gt;Next, you need to initialize your project. To do this, use the newly installed express-generator program to bootstrap your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;express --view pug blog
cd blog
npm install
npm start

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

&lt;/div&gt;



&lt;p&gt;The above command will initialize a new project called &lt;strong&gt;blog&lt;/strong&gt; , move you into the new project folder, install all project dependencies, and start up a web server.&lt;/p&gt;

&lt;p&gt;Once you’ve finished running the commands above, point your favorite browser to &lt;code&gt;http://localhost:3000&lt;/code&gt; and you should see your application running:&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fexpress-generator-page-0b86cb095fdd227d7b61051795d52a4a02d757fe3b320b9f8e6a0d5a2bec9c59.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fexpress-generator-page-0b86cb095fdd227d7b61051795d52a4a02d757fe3b320b9f8e6a0d5a2bec9c59.png" alt="express generator page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize Authentication
&lt;/h2&gt;

&lt;p&gt;Dealing with user authentication in web apps is a huge pain for every developer. This is where Okta shines: it helps you secure your web applications with minimal effort. To get started, you’ll need to create an OpenID Connect application in Okta. &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;Sign up for a forever-free developer account&lt;/a&gt; (or log in if you already have one).&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443.png" alt="Okta signup page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve logged in and land on the dashboard page, copy down the &lt;strong&gt;Org URL&lt;/strong&gt; pictured below. You will need this 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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d.png" alt="Okta Org URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then create a new application by browsing to the &lt;strong&gt;Applications&lt;/strong&gt; tab and clicking &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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b.png" alt="Okta app dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, click the &lt;strong&gt;Web&lt;/strong&gt; platform option (since our blog project is a web app).&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46.png" alt="Okta create app platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the settings page, enter the following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt; : Blog&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login redirect URIs&lt;/strong&gt; : &lt;code&gt;http://localhost:3000/users/callback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can leave all the other values unchanged.&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816.png" alt="Okta create app settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that your application has been created, copy down the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client secret&lt;/strong&gt; values on the following page, you’ll need them soon.&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-app-secrets-d4c5570e7679ca4e5af1c90f8fccc1bed0d880bed69eb4b9a9287aaf1e2398cf.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-app-secrets-d4c5570e7679ca4e5af1c90f8fccc1bed0d880bed69eb4b9a9287aaf1e2398cf.png" alt="Okta app secrets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, create a new authentication token. This will allow your app to talk to Okta to retrieve user information, among other things. To do this, click the &lt;strong&gt;API&lt;/strong&gt; tab at the top of the page followed by the &lt;strong&gt;Create Token&lt;/strong&gt; button. Give your token a name, preferably the same name as your application, then click &lt;strong&gt;Create Token&lt;/strong&gt;. Copy down this token value as you will need it soon.&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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-create-token-87e20254a5485f3482d1fc6a928df9590fac7b0c7a60fbffaca216078f91626f.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%2Ftutorial-build-a-basic-crud-app-with-node%2Fokta-create-token-87e20254a5485f3482d1fc6a928df9590fac7b0c7a60fbffaca216078f91626f.png" alt="Okta create token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dependencies
&lt;/h2&gt;

&lt;p&gt;The first thing you need to do in order to initialize your Express.js app is install all of the required dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install express@4.16.3
npm install @okta/oidc-middleware@0.1.2
npm install @okta/okta-sdk-nodejs@1.1.0
npm install sqlite3@4.0.1
npm install sequelize@4.38.0
npm install async@2.6.1
npm install slugify@1.3.0
npm install express-session@1.15.6

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Define Database Models with Sequelize
&lt;/h2&gt;

&lt;p&gt;The first thing I like to do when starting a new project is define what data my application needs to store, so I can model out exactly what data I’m handling.&lt;/p&gt;

&lt;p&gt;Create a new file named &lt;code&gt;./models.js&lt;/code&gt; and copy the following code inside of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Sequelize = require("sequelize");

const db = new Sequelize({
  dialect: "sqlite",
  storage: "./database.sqlite"
});

const Post = db.define("post", {
  title: { type: Sequelize.STRING },
  body: { type: Sequelize.TEXT },
  authorId: { type: Sequelize.STRING },
  slug: { type: Sequelize.STRING }
});

db.sync();

module.exports = { Post };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code initializes a new SQLite database that will be used to store the blog data and also defines a model called &lt;code&gt;Post&lt;/code&gt; which stores blog posts in the database. Each post has a title, a body, an author ID, and a slug field.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;title&lt;/code&gt; field will hold the title of a post, eg: “A Great Article”&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;body&lt;/code&gt; field will hold the body of the article as HTML, eg: “&lt;p&gt;My first post!&lt;/p&gt;”&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;authorId&lt;/code&gt; field will store the author’s unique ID. This is a common pattern in relational databases: store just the identifier of a linked resource so you can look up the author’s most up-to-date information later.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;slug&lt;/code&gt; field will store the URL-friendly version of the post’s title, eg: “a-great-article”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : If you’ve never used SQLite before, it’s amazing. It’s a database that stores your data in a single file. It’s great for building applications that don’t require a large amount of concurrency, like this simple blog.&lt;/p&gt;

&lt;p&gt;The call to &lt;code&gt;db.sync();&lt;/code&gt; at the bottom of the file will automatically create the database and all of the necessary tables once this JavaScript code runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize Your Express.js App
&lt;/h2&gt;

&lt;p&gt;The next thing I like to do after defining my database models is to initialize my application code. This typically involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configuring application settings&lt;/li&gt;
&lt;li&gt;Installing middlewares that provide functionality to the application&lt;/li&gt;
&lt;li&gt;Handling errors&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the &lt;code&gt;./app.js&lt;/code&gt; file and replace its contents with the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const createError = require("http-errors");
const express = require("express");
const logger = require("morgan");
const path = require("path");
const okta = require("@okta/okta-sdk-nodejs");
const session = require("express-session");
const ExpressOIDC = require("@okta/oidc-middleware").ExpressOIDC;

const blogRouter = require("./routes/blog");
const usersRouter = require("./routes/users");

const app = express();
const client = new okta.Client({
  orgUrl: "{yourOktaOrgUrl}",
  token: "{yourOktaToken}"
});

app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");

// Middleware
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "public")));

const oidc = new ExpressOIDC({
  issuer: "{yourOktaOrgUrl}/oauth2/default",
  client_id: "{yourOktaClientId}",
  client_secret: "{yourOktaClientSecret}",
  redirect_uri: "http://localhost:3000/users/callback",
  scope: "openid profile",
  routes: {
    login: {
      path: "/users/login"
    },
    callback: {
      path: "/users/callback",
      defaultRedirect: "/dashboard"
    }
  }
});

app.use(session({
  secret: "{aLongRandomString}",
  resave: true,
  saveUninitialized: false
}));

app.use(oidc.router);

app.use((req, res, next) =&amp;gt; {
  if (!req.userinfo) {
    return next();
  }

  client.getUser(req.userinfo.sub)
    .then(user =&amp;gt; {
      req.user = user;
      res.locals.user = user;
      next();
    });
});

// Routes
app.use("/", blogRouter);
app.use("/users", usersRouter);

// Error handlers
app.use(function(req, res, next) {
  next(createError(404));
});

app.use(function(err, req, res, next) {
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  res.status(err.status || 500);
  res.render("error");
});

module.exports = app;

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

&lt;/div&gt;



&lt;p&gt;Be sure to replace the placeholder variables with your actual Okta information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;{yourOktaOrgUrl}&lt;/code&gt; with the Org URL on your dashboard page&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;{yourOktaClientId}&lt;/code&gt; with the Client ID on your application page&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;{yourOktaClientSecret}&lt;/code&gt; with the Client secret on your application page&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;{aLongRandomString}&lt;/code&gt; with a long random string (just mash your fingers on the keyboard for a second)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s take a look at what this code does.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize Node.js Middlewares
&lt;/h3&gt;

&lt;p&gt;Middlewares in Express.js are functions that run on every request. There are many open source middlewares you can install and use to add functionality to your Express.js applications. The code below uses several popular Express.js middlewares, as well as defines some new ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Middleware
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "public")));

const oidc = new ExpressOIDC({
  issuer: "{yourOktaOrgUrl}/oauth2/default",
  client_id: "yourOktaClientId}",
  client_secret: "{yourOktaClientSecret}",
  redirect_uri: "http://localhost:3000/users/callback",
  scope: "openid profile",
  routes: {
    login: {
      path: "/users/login"
    },
    callback: {
      path: "/users/callback",
      defaultRedirect: "/dashboard"
    }
  }
});

app.use(session({
  secret: "{aLongRandomString}",
  resave: true,
  saveUninitialized: false
}));

app.use(oidc.router);

app.use((req, res, next) =&amp;gt; {
  if (!req.userinfo) {
    return next();
  }

  client.getUser(req.userinfo.sub)
    .then(user =&amp;gt; {
      req.user = user;
      res.locals.user = user;

      next();
    });
});

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

&lt;/div&gt;



&lt;p&gt;The first few middlewares are all standard stuff: they enable logging, parse form data, and serve static files. The interesting thing to take note of is the use of the &lt;code&gt;ExpressOIDC&lt;/code&gt; middleware.&lt;/p&gt;

&lt;p&gt;This middleware handles the OpenID Connect authentication logic of the application which supports login, logout, etc. The settings being passed into the &lt;code&gt;ExpressOIDC&lt;/code&gt; middleware are configuration options which dictate what URLs are used to log the user into the application, and where the user will be redirected once they’ve been logged in.&lt;/p&gt;

&lt;p&gt;The next middleware is the &lt;code&gt;session&lt;/code&gt; middleware. This middleware is responsible for managing user cookies and remembering who a user is. The &lt;code&gt;secret&lt;/code&gt; it takes must be a long random string you define and keep private. This secret makes it impossible for attackers to tamper with cookies.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;oidc.router&lt;/code&gt; middleware uses the settings you defined when creating &lt;code&gt;ExpressOIDC&lt;/code&gt; to create routes for handling user authentication. Whenever a user visits &lt;code&gt;/users/login&lt;/code&gt;, for instance, they’ll be taken to a login page. This line of code is what makes that possible.&lt;/p&gt;

&lt;p&gt;Finally, there’s a custom middleware. This middleware creates a &lt;code&gt;req.user&lt;/code&gt; object that you will be able to use later on to more easily access a currently logged in user’s personal information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize Node.js Routes
&lt;/h3&gt;

&lt;p&gt;The route code tells Express.js what code to run when a user visits a particular URL. Here is the route code from the &lt;code&gt;./app.js&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;// Routes
app.use("/", blogRouter);
app.use("/users", usersRouter);

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

&lt;/div&gt;



&lt;p&gt;This code tells Express.js that in our (yet to be created) blog and user route files there are functions that should be executed when certain URLs are hit. If a user visits a URL starting with &lt;code&gt;/users&lt;/code&gt;, Express.js will look for other matching URLs in the user routes file. If a user visits any URLs starting with the &lt;code&gt;/&lt;/code&gt; URL, Express.js will look in the blog routes file to see what to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize Error Handlers
&lt;/h3&gt;

&lt;p&gt;The last bit of code in our app above is the error-handling middlewares.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Error handlers
app.use(function(req, res, next) {
  next(createError(404));
});

app.use(function(err, req, res, next) {
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  res.status(err.status || 500);
  res.render("error");
});

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

&lt;/div&gt;



&lt;p&gt;These middlewares will run if any 4XX or 5XX type errors occur. In both cases, they will render a simple web page to the user showing them the error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Express.js Views
&lt;/h2&gt;

&lt;p&gt;Views in Express.js are the equivalent of HTML templates—they’re the place you store front-end code and logic. The views you’ll use in this project will use the &lt;a href="https://pugjs.org/api/getting-started.html" rel="noopener noreferrer"&gt;Pug&lt;/a&gt; templating language which is one of the most popular.&lt;/p&gt;

&lt;p&gt;Remove your existing views by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm views/*

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

&lt;/div&gt;



&lt;p&gt;Next, create a &lt;code&gt;./views/layout.pug&lt;/code&gt; file. This is a base “layout” template that all other templates will inherit from. It defines common HTML, includes the &lt;a href="https://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; CSS library, and also defines a simple navigation menu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;block variables
  - var selected = 'Home'

doctype html
html(lang='en')
  head
    meta(charset='utf-8')
    meta(name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no')
    link(rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm' crossorigin='anonymous')
    link(rel='stylesheet', href='/stylesheets/style.css')
    title Blog: #{title}
  body
    div.d-flex.flex-column.flex-md-row.align-items-center.p-3.px-md-4.mb-3.bg-white.border-bottom.box-shadow
      h5.my-0.mr-md-auto.font-weight-normal Blog
      nav.my-2.my-md-0.mr-md-3
        a.p-2.text-dark(href="/", title="Home") Home

        if user == undefined
          a.p-2.text-dark(href="/users/login") Log In
        else
          a.p-2.text-dark(href="/dashboard") Dashboard
          a.p-2.text-dark(href="/users/logout") Logout
    .container
      block content

    hr.bottom
    footer.
      Built with #[a(href='https://expressjs.com/') Express.js], login powered by #[a(href='https://developer.okta.com/') Okta].

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

&lt;/div&gt;



&lt;p&gt;Next, create the &lt;code&gt;./views/error.pug&lt;/code&gt; file. This page will be shown when an error occurs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block content
  h1= message
  h2= error.status
  pre #{error.stack}

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

&lt;/div&gt;



&lt;p&gt;Next, create the &lt;code&gt;./views/unauthenticated.pug&lt;/code&gt; file. This page will be shown when a user tries to visit a page but they aren’t 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;extends layout

block variables
  - var title = "Unauthenticated"

block content
  .unauthenticated
    h2.text-center Whoops!
    p.
      You must be signed in to view this page. Please #[a(href="/users/login", title="Login") login] to view this page.

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

&lt;/div&gt;



&lt;p&gt;Now define the &lt;code&gt;./views/index.pug&lt;/code&gt; template. This is the homepage of the website and lists all the current blog posts ordered by date.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block variables
  - var title = "Home"

block content
  h2.text-center Recent Posts

  if posts == null
    p.empty.text-center Uh oh. There are no posts to view!

  .posts
    ul
      each post in posts
        .row
          .offset-sm-2.col-sm-8
            li
              a(href="/" + post.slug, title=post.title)= post.title
              span   by #{post.authorName}

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

&lt;/div&gt;



&lt;p&gt;The next view to define is &lt;code&gt;./views/post.pug&lt;/code&gt; which displays a single blog post.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block variables
  - var title = post.title

block content
  h2.text-center= title

  .row
    .offset-sm-2.col-sm-8
      .body !{post.body}
      p.author Written by #{post.authorName}

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

&lt;/div&gt;



&lt;p&gt;Now create the file &lt;code&gt;./views/edit.pug&lt;/code&gt; which contains the blog post editing page markup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block variables
  - var title = post.title

block content
  h2.text-center Edit Post

  .row
    .offset-sm-2.col-sm-8
      form(method="post")
        .form-group
          label(for="title") Post Title
          input.form-control#title(type="text", name="title", value=post.title, required)
        .form-group
          label(for="body") Post Body
          textarea.form-control#post(name="body", rows="6", required)= post.body
        button.btn.btn-primary.submit-btn(type="submit") Update

  .row
    .offset-sm-2.col-sm-8
      .body !{post.body}
      p.author Written by #{post.authorName}

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

&lt;/div&gt;



&lt;p&gt;Finally, create &lt;code&gt;./views/dashboard.pug&lt;/code&gt; which will render the dashboard page that users will see once they’ve logged in. This page allows a user to create a new post as well as edit and delete their existing posts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends layout

block variables
  - var title = "Dashboard"

block content
  .row
    .offset-sm-2.col-sm-8
      h2 Create a Post

  if post != undefined
    .row
      .offset-sm-2.col-sm-8
        .alert.alert-success(role="alert").text-center
          p Your new post was created successfully! #[a(href="/" + post.slug) View it?]

  .row
    .offset-sm-2.col-sm-8
      form(method="post")
        .form-group
          label(for="title") Post Title
          input.form-control#title(type="text", name="title", placeholder="Title", required)
        .form-group
          label(for="body") Post Body
          textarea.form-control#post(name="body", rows="6", required)
        button.btn.btn-primary.submit-btn(type="submit") Submit

  .row
    .offset-sm-2.col-sm-8
      h2.your-posts Your Posts
      ul.edit
        each post in posts
          li
            a(href="/" + post.slug, title=post.title)= post.title
            form.hidden(method="post", action="/" + post.slug + "/delete")
              button.btn.btn-outline-danger.delete Delete
            a(href="/" + post.slug + "/edit", title=post.title)
              button.btn.btn-outline-secondary Edit

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Styles
&lt;/h2&gt;

&lt;p&gt;I’m not much of a web designer (that’s why I like using Bootstrap), but every project needs a bit of visual flair. I’ve done my best to create some simple CSS styling.&lt;/p&gt;

&lt;p&gt;Since CSS is straightforward and not the focus of this tutorial, you can simply copy the CSS below into the &lt;code&gt;./public/stylesheets/style.css&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;footer {
  text-align: center;
  font-style: italic;
  margin-top: 1em;
}

.nav {
  float: right;
}

h2 {
  margin-bottom: 2em;
}

.posts ul {
  list-style-type: none;
}

.posts a {
  font-size: 1.3em;
  text-decoration: underline;
  color: #212529;
}

.posts span {
  font-size: 1.1em;
  float: right;
}

.empty {
  font-size: 2em;
  margin-bottom: 5em;
}

.container {
  padding-top: 2em;
}

.unauthenticated p {
  font-size: 1.3em;
  text-align: center;
}

hr.bottom {
  margin-top: 4em;
}

.submit-btn {
  float: right;
}

.alert p {
  font-size: 1.1em;
}

.author {
  font-size: 1.2em;
  margin-top: 2em;
}

.body {
  margin-top: 2em;
  font-size: 1.2em;
}

.edit {
  padding-left: 0;
}

.edit a {
  text-decoration: underline;
  color: #212529;
  font-size: 1.5em;
}

.edit li {
  list-style-type: none;
  line-height: 2.5em;
}

.edit button {
  float: right;
}

.delete {
  margin-left: 1em;
}

.your-posts {
  margin-top: 2em;
}

.hidden {
  display: inline;
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Routes
&lt;/h2&gt;

&lt;p&gt;Routes are where the real action happens in any Express.js application. They dictate what happens when a user visits a particular URL.&lt;/p&gt;

&lt;p&gt;To get started, remove the existing routes that the express-generator application created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rm routes/*

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

&lt;/div&gt;



&lt;p&gt;Next, create the two route files that you’ll need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch routes/{blog.js,users.js}

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;./routes/blog.js&lt;/code&gt; file will contain all of the routes related to blog functionality. The &lt;code&gt;./routes/users.js&lt;/code&gt; file will contain the routes related to user functionality. While you could always put all your logic in the main &lt;code&gt;./app.js&lt;/code&gt; file, keeping your routes in separate purpose-based files is a good idea.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create User Routes
&lt;/h3&gt;

&lt;p&gt;Since Okta’s &lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/oidc-middleware" rel="noopener noreferrer"&gt;oidc-middleware library&lt;/a&gt; is already handling user authentication for the application, there isn’t a lot of user-facing functionality we need to create.&lt;/p&gt;

&lt;p&gt;The only route you need to define that relates to user management is a logout route — this route will log the user out of their account and redirect them to the homepage of the site. While the oidc-middleware library provides a logout helper, it doesn’t create an actual route.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;./routes/users.js&lt;/code&gt; file and copy in the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require("express");

const router = express.Router();

// Log a user out
router.get("/logout", (req, res, next) =&amp;gt; {
  req.logout();
  res.redirect("/");
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;The way to understand this route is simple. When a user visits the &lt;code&gt;/logout&lt;/code&gt; URL, a function will run that:&lt;/p&gt;

&lt;p&gt;Uses the oidc-middleware library to log the user out of their accountRedirects the now logged-out user to the homepage of the site&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Blog Routes
&lt;/h3&gt;

&lt;p&gt;Since the application you’re building is a blog, the last big piece of functionality you need add is the actual blog route code. This is what will dictate how the blog actually works: how to create posts, edit posts, delete posts, etc.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;./routes/blog.js&lt;/code&gt; file and copy in the following code. Don’t worry if it looks like a lot all at once - I’ll walk you through each route in detail below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const async = require("async");
const express = require("express");
const okta = require("@okta/okta-sdk-nodejs");
const sequelize = require("sequelize");
const slugify = require("slugify");

const models = require("../models");

const client = new okta.Client({
  orgUrl: "{yourOktaOrgUrl}",
  token: "{yourOktaToken}"
});
const router = express.Router();

// Only let the user access the route if they are authenticated.
function ensureAuthenticated(req, res, next) {
  if (!req.user) {
    return res.status(401).render("unauthenticated");
  }

  next();
}

// Render the home page and list all blog posts
router.get("/", (req, res) =&amp;gt; {
  models.Post.findAll({
    order: sequelize.literal("createdAt DESC")
  }).then(posts =&amp;gt; {
    let postData = [];

    async.eachSeries(posts, (post, callback) =&amp;gt; {
      post = post.get({ plain: true });
      client.getUser(post.authorId).then(user =&amp;gt; {
        postData.push({
          title: post.title,
          body: post.body,
          createdAt: post.createdAt,
          authorName: user.profile.firstName + " " + user.profile.lastName,
          slug: post.slug
        });
        callback();
      }).catch(err =&amp;gt; {
        postData.push({
          title: post.title,
          body: post.body,
          createdAt: post.createdAt,
          slug: post.slug
        });
        callback();
      });
    }, err =&amp;gt; {
      return res.render("index", { posts: postData });
    });
  });
});

// Render the user dashboard
router.get("/dashboard", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.findAll({
    where: {
      authorId: req.user.id
    },
    order: sequelize.literal("createdAt DESC")
  }).then(posts =&amp;gt; {
    let postData = [];

    posts.forEach(post =&amp;gt; {
      postData.push(post.get({ plain: true }));
    });

    return res.render("dashboard", { posts: postData });
  });
});

// Create a new post
router.post("/dashboard", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.create({
    title: req.body.title,
    body: req.body.body,
    authorId: req.user.id,
    slug: slugify(req.body.title).toLowerCase()
  }).then(newPost =&amp;gt; {
    models.Post.findAll({
      where: {
        authorId: req.user.id
      },
      order: sequelize.literal("createdAt DESC")
    }).then(posts =&amp;gt; {
      let postData = [];

      posts.forEach(post =&amp;gt; {
        postData.push(post.get({ plain: true }));
      });

      res.render("dashboard", { post: newPost, posts: postData });
    });
  });
});

// Render the edit post page
router.get("/:slug/edit", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug,
      authorId: req.user.id
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post = post.get({ plain: true });
    client.getUser(post.authorId).then(user =&amp;gt; {
      post.authorName = user.profile.firstName + " " + user.profile.lastName;
      res.render("edit", { post });
    });
  });
});

// Update a post
router.post("/:slug/edit", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug,
      authorId: req.user.id
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post.update({
      title: req.body.title,
      body: req.body.body,
      slug: slugify(req.body.title).toLowerCase()
    }).then(() =&amp;gt; {
      post = post.get({ plain: true });
      client.getUser(post.authorId).then(user =&amp;gt; {
        post.authorName = user.profile.firstName + " " + user.profile.lastName;
        res.redirect("/" + slugify(req.body.title).toLowerCase());
      });
    });
  });
});

// Delete a post
router.post("/:slug/delete", (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug,
      authorId: req.user.id
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post.destroy();
    res.redirect("/dashboard");
  });
});

// View a post
router.get("/:slug", (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post = post.get({ plain: true });
    client.getUser(post.authorId).then(user =&amp;gt; {
      post.authorName = user.profile.firstName + " " + user.profile.lastName;
      res.render("post", { post });
    });
  });
});

module.exports = router;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : Make sure you substitute in your values for the placeholder variables towards the top of this file. You need to replace &lt;code&gt;{yourOktaOrgUrl}&lt;/code&gt; and &lt;code&gt;{yourOktaToken}&lt;/code&gt; with the appropriate values.&lt;/p&gt;

&lt;p&gt;This is a lot of code, so let’s take a look at each route and how it works.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create an Authentication Helper
&lt;/h4&gt;

&lt;p&gt;The first function you’ll notice in the blog routes is the &lt;code&gt;ensureAuthenticated&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Only let the user access the route if they are authenticated.
function ensureAuthenticated(req, res, next) {
  if (!req.user) {
    return res.status(401).render("unauthenticated");
  }

  next();
}

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

&lt;/div&gt;



&lt;p&gt;This function is a special middleware you’ll use later on that will render the &lt;code&gt;unauthenticated.pug&lt;/code&gt; view you created earlier to tell the user they don’t have access to view the page unless they log in.&lt;/p&gt;

&lt;p&gt;This middleware works by looking for the &lt;code&gt;req.user&lt;/code&gt; variable which, if it doesn’t exist, means that the user is not currently logged in. This will be helpful later on to make sure that only logged in users can access certain pages of the site (for instance, the page that allows a user to create a new blog post).&lt;/p&gt;

&lt;h4&gt;
  
  
  Create the Homepage
&lt;/h4&gt;

&lt;p&gt;The index route (aka: “homepage route”) is what will run when the user visits the root of the site. It will display all blog posts ordered by date and not much else. Here’s the route code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Render the home page and list all blog posts
router.get("/", (req, res) =&amp;gt; {
  models.Post.findAll({
    order: sequelize.literal("createdAt DESC")
  }).then(posts =&amp;gt; {
    let postData = [];

    async.eachSeries(posts, (post, callback) =&amp;gt; {
      post = post.get({ plain: true });
      client.getUser(post.authorId).then(user =&amp;gt; {
        postData.push({
          title: post.title,
          body: post.body,
          createdAt: post.createdAt,
          authorName: user.profile.firstName + " " + user.profile.lastName,
          slug: post.slug
        });
        callback();
      }).catch(err =&amp;gt; {
        postData.push({
          title: post.title,
          body: post.body,
          createdAt: post.createdAt,
          slug: post.slug
        });
        callback();
      });
    }, err =&amp;gt; {
      return res.render("index", { posts: postData });
    });
  });
});

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

&lt;/div&gt;



&lt;p&gt;The way this works is by first using &lt;a href="http://docs.sequelizejs.com/" rel="noopener noreferrer"&gt;Sequelize.js&lt;/a&gt; to retrieve a list of all blog posts from the database ordered by the &lt;code&gt;createdAt&lt;/code&gt; field. Whenever a new blog post is stored in the database, Sequelize.js automatically assigns it both a &lt;code&gt;createdAt&lt;/code&gt; and &lt;code&gt;updatedAt&lt;/code&gt; time field.&lt;/p&gt;

&lt;p&gt;Once a list of posts have been returned from the database you will iterate over each post retrieving it in JSON format, then use &lt;a href="https://github.com/okta/okta-sdk-nodejs" rel="noopener noreferrer"&gt;Okta’s Node SDK&lt;/a&gt; to retrieve the author’s information via the authorId field.&lt;/p&gt;

&lt;p&gt;Finally, you’ll build an array consisting of all the blog posts alongside the author’s name, and will render the &lt;code&gt;index.pug&lt;/code&gt; template which then takes that data and displays the full web page.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create the Dashboard Routes
&lt;/h4&gt;

&lt;p&gt;The dashboard page is the first page users will see after logging in. It will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow users to create a new blog post&lt;/li&gt;
&lt;li&gt;Show users a list of their previously created blog posts&lt;/li&gt;
&lt;li&gt;Provide buttons that allow a user to edit or delete previously created blog posts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s the code that powers the dashboard route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Render the user dashboard
router.get("/dashboard", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.findAll({
    where: {
      authorId: req.user.id
    },
    order: sequelize.literal("createdAt DESC")
  }).then(posts =&amp;gt; {
    let postData = [];

    posts.forEach(post =&amp;gt; {
      postData.push(post.get({ plain: true }));
    });

    return res.render("dashboard", { posts: postData });
  });
});

// Create a new post
router.post("/dashboard", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.create({
    title: req.body.title,
    body: req.body.body,
    authorId: req.user.id,
    slug: slugify(req.body.title).toLowerCase()
  }).then(newPost =&amp;gt; {
    models.Post.findAll({
      where: {
        authorId: req.user.id
      },
      order: sequelize.literal("createdAt DESC")
    }).then(posts =&amp;gt; {
      let postData = [];

      posts.forEach(post =&amp;gt; {
        postData.push(post.get({ plain: true }));
      });

      res.render("dashboard", { post: newPost, posts: postData });
    });
  });
});

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

&lt;/div&gt;



&lt;p&gt;Note that there are technically two routes here. The first route function is run when a user issues a GET request for the &lt;code&gt;/dashboard&lt;/code&gt; page, while the second route is run when a user issues a &lt;code&gt;POST&lt;/code&gt; request for the &lt;code&gt;/dashboard&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;The first route retrieves a list of all blog posts this user has created, then renders the dashboard page. Note how it uses the &lt;code&gt;ensureAuthenticated&lt;/code&gt; middleware we created earlier. By inserting the &lt;code&gt;ensureAuthenticated&lt;/code&gt; middleware into the route, this guarantees that this route code will only execute if a currently logged in user is visiting this page.&lt;/p&gt;

&lt;p&gt;If a user chooses to create a new blog post, that will trigger a POST request to the &lt;code&gt;/dashboard&lt;/code&gt; URL, which is what will eventually run the second dashboard route shown above.&lt;/p&gt;

&lt;p&gt;This route uses Sequelize.js to create a new database entry storing the blog posts and author details, then renders the dashboard page once more.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create the Edit Routes
&lt;/h4&gt;

&lt;p&gt;The edit routes control the pages that allow a user to edit one of their existing blog posts. The code that makes this work is shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Render the edit post page
router.get("/:slug/edit", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug,
      authorId: req.user.id
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post = post.get({ plain: true });
    client.getUser(post.authorId).then(user =&amp;gt; {
      post.authorName = user.profile.firstName + " " + user.profile.lastName;
      res.render("edit", { post });
    });
  });
});

// Update a post
router.post("/:slug/edit", ensureAuthenticated, (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug,
      authorId: req.user.id
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post.update({
      title: req.body.title,
      body: req.body.body,
      slug: slugify(req.body.title).toLowerCase()
    }).then(() =&amp;gt; {
      post = post.get({ plain: true });
      client.getUser(post.authorId).then(user =&amp;gt; {
        post.authorName = user.profile.firstName + " " + user.profile.lastName;
        res.redirect("/" + slugify(req.body.title).toLowerCase());
      });
    });
  });
});

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

&lt;/div&gt;



&lt;p&gt;These routes by matching a variable pattern URL. If the user visits a URL that looks like &lt;code&gt;/&amp;lt;something&amp;gt;/edit&lt;/code&gt;, then the edit route will run. Because the URL pattern in the route is defined as &lt;code&gt;/:slug/edit&lt;/code&gt;, Express.js will pass along the URL route in the &lt;code&gt;req.params.slug&lt;/code&gt; variable so you can use it.&lt;/p&gt;

&lt;p&gt;These routes handle rendering the edit page as well as updating existing posts when needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create the Delete Route
&lt;/h4&gt;

&lt;p&gt;The delete route is simple: if a user sends a POST request to the URL &lt;code&gt;/&amp;lt;post-url&amp;gt;/delete&lt;/code&gt;, then Sequelize.js will destroy the post from the database.&lt;/p&gt;

&lt;p&gt;Here’s the code that makes this work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Delete a post
router.post("/:slug/delete", (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug,
      authorId: req.user.id
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post.destroy();
    res.redirect("/dashboard");
  });
});

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Create the Display Route
&lt;/h4&gt;

&lt;p&gt;The display route is the simplest of them all: it renders a specific blog post on a page. It works much like the other routes above by using variable URL patterns.&lt;/p&gt;

&lt;p&gt;When a user visits a URL like &lt;code&gt;/my-great-article&lt;/code&gt;, this route will run, query the database for any blog posts whose slug is &lt;code&gt;my-great-article&lt;/code&gt;, then display that post on a page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// View a post
router.get("/:slug", (req, res, next) =&amp;gt; {
  models.Post.findOne({
    where: {
      slug: req.params.slug
    }
  }).then(post =&amp;gt; {
    if (!post) {
      return res.render("error", {
        message: "Page not found.",
        error: {
          status: 404,
        }
      });
    }

    post = post.get({ plain: true });
    client.getUser(post.authorId).then(user =&amp;gt; {
      post.authorName = user.profile.firstName + " " + user.profile.lastName;
      res.render("post", { post });
    });
  });
});

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test Your New CRUD App!
&lt;/h2&gt;

&lt;p&gt;By this point, you’ve built a fully functional Node.js website using Express.js and Okta. To test it out, run the following command to start up your web server then visit &lt;code&gt;http://localhost:3000&lt;/code&gt; in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm start

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

&lt;/div&gt;



&lt;p&gt;If you were able to copy the code properly, you should be able to log in, create posts, edit posts, and delete posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do More With Node!
&lt;/h2&gt;

&lt;p&gt;I hope you enjoyed building a simple CRUD app with Node.js and Express.js. I’ve found that Express.js has a rich ecosystem of libraries and tools to make web development simple and fun. You can find the source code for the example created in this tutorial &lt;a href="https://github.com/rdegges/okta-express-blog" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you’d like to learn more about building web apps in Node, you might want to check out these other great posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/oktadev/build-secure-node-authentication-with-passportjs-and-openid-connect-3a60-temp-slug-6741213"&gt;Build Secure Node Authentication with Passport.js and OpenID Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/02/06/build-user-registration-with-node-react-and-okta" rel="noopener noreferrer"&gt;Build User Registration with Node, React, and Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/oktadev/simple-node-authentication-366l-temp-slug-673868"&gt;Simple Node Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/02/15/build-crud-app-vuejs-node" rel="noopener noreferrer"&gt;Build a Basic CRUD App with Vue.js and Node&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re interested in learning more about how the underlying authentication components work (OpenID Connect), you may be interested in our &lt;a href="https://developer.okta.com/blog/2017/07/25/oidc-primer-part-1" rel="noopener noreferrer"&gt;OpenID Connect primer series&lt;/a&gt; which explains everything you need to know about OpenID Connect as a developer.&lt;/p&gt;

&lt;p&gt;Finally, please &lt;a href="https://twitter.com/OktaDev" rel="noopener noreferrer"&gt;follow @oktadev on Twitter&lt;/a&gt; to find more great resources like this, request other topics for us to write about, and follow along with our new open source libraries and projects!&lt;/p&gt;

&lt;p&gt;And… If you have any questions, please leave a comment below!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>node</category>
    </item>
    <item>
      <title>What Happens If Your JWT Is Stolen?</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Wed, 20 Jun 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/what-happens-if-your-jwt-is-stolen-298d</link>
      <guid>https://dev.to/oktadev/what-happens-if-your-jwt-is-stolen-298d</guid>
      <description>

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EJ-Laov8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/stolen-jwt-813423a2a0c04d9c99e58aea4bede15081038d6e3e41b98c619734c1b8967512.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EJ-Laov8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/stolen-jwt-813423a2a0c04d9c99e58aea4bede15081038d6e3e41b98c619734c1b8967512.png" alt="Stolen JWT"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of us know what happens if our user credentials (email and password) are discovered by an attacker: they can log into our account and wreak havoc. But a lot of modern applications are using JSON Web Tokens (JWTs) to manage user sessions—what happens if a JWT is compromised? Because more and more applications are using token-based authentication, this question is increasingly relevant to developers and critical to understand if you’re building any sort of application that uses token-based authentication.&lt;/p&gt;

&lt;p&gt;To help explain the concepts fully, I’ll walk you through what tokens are, how they’re used, and what happens when they’re stolen. Finally: I’ll cover what you should actually do if your token has been stolen, and how to prevent this in the future.&lt;/p&gt;

&lt;p&gt;This post was inspired by this &lt;a href="https://stackoverflow.com/questions/34259248/what-if-jwt-is-stolen"&gt;StackOverflow question&lt;/a&gt;. My response to that question has become one of my most popular responses on StackOverflow to date!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Token?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CaDbvtER--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/shrug-1ad78de3fb2a4efbec8eb87a486bb48914454a642a4fb4d3d55dfe83db8a3d93.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CaDbvtER--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/shrug-1ad78de3fb2a4efbec8eb87a486bb48914454a642a4fb4d3d55dfe83db8a3d93.jpg" alt="Shrug"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A token in the context of web development is nothing more than an arbitrary value that represents a session. Tokens can be strings like “abc123” or randomly generated IDs like “48ff796e-8c8a-46b9-9f25-f883c14734ea”.&lt;/p&gt;

&lt;p&gt;A token’s purpose is to help a server remember who somebody is. Take API services, for example: if you have an API key that lets you talk to an API service from your server-side application, that API key is what the API service uses to “remember” who you are, look up your account details, and allow (or disallow) you from making a request. In this example, your API key is your “token”, and it allows you to access the API.&lt;/p&gt;

&lt;p&gt;However, when most people talk about tokens today, they’re actually referring to JWTs (for better or &lt;a href="https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens"&gt;worse&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a JSON Web Token (JWT)?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oclBPlK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/jwt-778843a03acacfc994840c1b614464e512ccf5f520240072b593f521d78ecba5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oclBPlK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/jwt-778843a03acacfc994840c1b614464e512ccf5f520240072b593f521d78ecba5.png" alt="JSON Web Token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tools.ietf.org/html/rfc7519"&gt;JSON Web Tokens&lt;/a&gt; are special types of tokens that are structured in such a way that makes them convenient to use over the web. They have a handful of defining traits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;They are represented as normal strings.&lt;/strong&gt; Here’s a real JWT:
&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlJhbmRhbGwgRGVnZ2VzIiwiaWF0IjoxNTE2MjM5MDIyfQ.sNMELyC8ohN8WF_WRnRtdHMItOVizcscPiWsQJX9hmw

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



&lt;p&gt;Because JWTs are just URL safe strings, they’re easy to pass around via URL parameters, etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;They contain JSON-encoded data.&lt;/strong&gt; This means you can have your JWT store as much JSON data as you want, and you can decode your token string into a JSON object. This makes them convenient for embedding information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;They’re cryptographically signed.&lt;/strong&gt; Understanding how this works is a &lt;a href="https://en.wikipedia.org/wiki/Digital_signature"&gt;topic unto itself&lt;/a&gt;. For now, just know that it means any trusted party who has a JWT can tell whether or not the token has been modified or changed. This means if your application or API service generates a token that says someone is a “free” user and someone later alters the token to say they are an “admin” user, you’ll be able to detect this and act accordingly. This property makes JWTs useful for sharing information between parties over the web where trust is difficult to come by.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a small code snippet which creates and validates a JWT in JavaScript using the &lt;a href="https://github.com/jwtk/njwt"&gt;njwt&lt;/a&gt; library. This example is purely here to show you at a glance how to create a JWT, embed some JSON data in it, and validate it.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const njwt = require("njwt");
const secureRandom = require("secure-random");

// This is a "secret key" that the creator of the JWT must keep private.
var key = secureRandom(256, { type: "Buffer" });

// This is the JSON data embedded in the token.
var claims = {
  iss: "https://api.com",
  sub: "someuserid",
  scope: "freeUser",
  favoriteColor: "black"
};

// Create a JWT
var jwt = njwt.create(claims, key);

// Log the JWT
console.log(jwt);
// Jwt {
// header: JwtHeader { typ: 'JWT', alg: 'HS256' },
// body:
// JwtBody {
// iss: 'https://api.com',
// sub: 'someuserid',
// scope: 'freeUser',
// favoriteColor: 'black',
// jti: '903c5447-ebfd-43e8-8f4d-b7cc5922f5ec',
// iat: 1528824349,
// exp: 1528827949 },
// signingKey: &amp;lt;Buffer 9c e9 48 a7 b3 c9 87 be 5f 59 90 a5 08 02 9b 98 5c 5e 1c 29 3f b0 33 c5 8c c8 f9 c8 3e 35 f0 7c 20 a0 aa 65 cc 98 47 b6 31 c5 5c d6 4e 6e 25 29 2b d3 ... &amp;gt; }

// The JWT in compacted form (ready for sending over the network)
var token = jwt.compact();

// Log the compacted JWT
console.log(jwt.compact());
// eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwaS5jb20iLCJzdWIiOiJzb21ldXNlcmlkIiwic2NvcGUiOiJmcmVlVXNlciIsImZhdm9yaXRlQ29sb3IiOiJibGFjayIsImp0aSI6IjkwM2M1NDQ3LWViZmQtNDNlOC04ZjRkLWI3Y2M1OTIyZjVlYyIsImlhdCI6MTUyODgyNDM0OSwiZXhwIjoxNTI4ODI3OTQ5fQ.y7ad-nUsHAkI8a5bixYnr_v0vStRqnzsT4bbWGAM2vw

// Verify the JWT using the secret key
njwt.verify(token, key, (err, verifiedJwt) =&amp;gt; {
  if (err) throw err;
  console.log("The JWT has been verified and can be trusted!");
  // The JWT has been verified and can be trusted!
});

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



&lt;h2&gt;
  
  
  How are JSON Web Tokens Used?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xmc1N-9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/how-are-jwts-used-916bd87556468089f02086c3900c8f30db0e48231272a374e7537b6eeca80338.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xmc1N-9c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/how-are-jwts-used-916bd87556468089f02086c3900c8f30db0e48231272a374e7537b6eeca80338.jpg" alt="How are JSON Web Tokens used?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JWTs are typically used as session identifiers for web applications, mobile applications, and API services. But, unlike traditional session identifiers which act as nothing more than a pointer to actual user data on the server-side, JWTs typically contain user data directly.&lt;/p&gt;

&lt;p&gt;The principal reason JWTs have become popular in recent years (having only been around since 2014) is that they can contain arbitrary JSON data. The touted benefit of a JWT over a traditional session ID is that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWTs are stateless and can contain user data directly&lt;/li&gt;
&lt;li&gt;Because JWTs are stateless, no server-side session needs to be implemented (no session database, session cache, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because JWTs are stateless, when a server-side application receives a JWT, it can validate it using only the “secret key” that was used to create it — thereby avoiding the performance penalty of talking to a database or cache on the backend, which adds latency to each request.&lt;/p&gt;

&lt;p&gt;With that said, let’s take a look at how a JWT would typically be used in a modern web application.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A client (a browser or mobile client, typically) will visit some sort of login page&lt;/li&gt;
&lt;li&gt;The client will send their credentials to the server-side application&lt;/li&gt;
&lt;li&gt;The server-side application will validate the user’s credentials, typically an email address and password, then generate a JWT that contains the user’s information. The information embedded in the JWT will typically be:&lt;/li&gt;
&lt;li&gt;The user’s first and last name&lt;/li&gt;
&lt;li&gt;The user’s email address or username&lt;/li&gt;
&lt;li&gt;The user’s ID (for server-side lookups, if necessary)&lt;/li&gt;
&lt;li&gt;The user’s permissions (what are they allowed to do?)&lt;/li&gt;
&lt;li&gt;Any other data that is relevant to the application being used&lt;/li&gt;
&lt;li&gt;The server-side application will return this token to the client&lt;/li&gt;
&lt;li&gt;The client will then store this token so that it can be used to identify itself in the future. For web applications, this might mean the client stores the token in &lt;a href="https://www.rdegges.com/2018/please-stop-using-local-storage/"&gt;HTML5 Local Storage&lt;/a&gt;. For server-side API clients, this might mean storing the token on disk or in a secret store.&lt;/li&gt;
&lt;li&gt;When the client makes requests to the server in the future, it will embed the JWT in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization"&gt;HTTP Authorization header&lt;/a&gt; to identify itself&lt;/li&gt;
&lt;li&gt;When the server-side application receives a new incoming request, it will check to see if an HTTP Authorization header exists, and if so, it will parse out the token and validate it using the “secret key”&lt;/li&gt;
&lt;li&gt;Finally, the server-side application will process the request if the token is valid and the cycle will be complete&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short: JWTs are used to identify a client. They are keys to the kingdom as far as the client is concerned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens if Your JSON Web Token is Stolen?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9VCuCM4w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/angry-rage-face-ff14143170c6493b0d0090b1c7edbff81a8ed6c55325a25bb11c7ce3d12593fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9VCuCM4w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/angry-rage-face-ff14143170c6493b0d0090b1c7edbff81a8ed6c55325a25bb11c7ce3d12593fb.png" alt="Angry Rage Face"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short: it’s bad, &lt;em&gt;real bad&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Because JWTs are used to identify the client, if one is stolen or compromised, an attacker has full access to the user’s account in the same way they would if the attacker had instead compromised the user’s username and password.&lt;/p&gt;

&lt;p&gt;For instance, if an attacker gets ahold of your JWT, they could start sending requests to the server identifying themselves as you and do things like make service changes, user account updates, etc. Once an attacker has your JWT it is game over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BUT&lt;/strong&gt; , there is one thing that makes a stolen JWT slightly less bad than a stolen username and password: &lt;em&gt;timing&lt;/em&gt;. Because JWTs can be configured to automatically expire after a set amount of time (a minute, an hour, a day, whatever), attackers can only use your JWT to access the service until it expires.&lt;/p&gt;

&lt;p&gt;In theory, that sounds great, right? One of the ways token authentication is said to make authentication more “secure” is via short-lived tokens. That’s one of the core reasons token-based authentication has really taken off in recent years: you can automatically expire tokens and mitigate the risk of relying on forever-cached “stateless” tokens.&lt;/p&gt;

&lt;p&gt;In the security world, after all, relying on cached data to make sensitive decisions like who can log into a service and what they can do is considered a bad thing. Because tokens are stateless and allow for some speed improvements over traditional session authentication, the only way in which they can remain somewhat “secure” is by limiting their lifespan so they don’t cause too much harm when compromised.&lt;/p&gt;

&lt;p&gt;The only problem here is that if an attacker was able to steal your token in the first place, they’re likely able to do it once you get a new token as well. The most common ways this happens is by man-in-the-middling (MITM) your connection or getting access to the client or server directly. And unfortunately, in these scenarios, even the shortest-lived JWTs won’t help you at all.&lt;/p&gt;

&lt;p&gt;In general, tokens should be treated like passwords and protected as such. They should never be publicly shared and should be kept in secure data stores. For browser-based applications, this means never storing your tokens in &lt;a href="https://www.rdegges.com/2018/please-stop-using-local-storage/"&gt;HTML5 Local Storage&lt;/a&gt; and instead storing tokens in server-side cookies that are not accessible to JavaScript.&lt;/p&gt;

&lt;p&gt;In general, token-based authentication does not provide any additional security over typical session-based authentication relying on opaque session identifiers. While there are certainly a good number of use cases for token-based authentication, knowing how the technology works and where your weak spots are is essential.&lt;/p&gt;

&lt;p&gt;Another interesting thing to consider is that &lt;strong&gt;in some cases, a stolen JWT can actually be &lt;em&gt;worse&lt;/em&gt; than a stolen username and password&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s pretend, for a moment, that your username and password have been compromised. In this scenario, if the app you’re logging into is protected with multi-factor authentication, an attacker needs to bypass additional identity proofing mechanisms in order to gain access to your account.&lt;/p&gt;

&lt;p&gt;While guessing or brute-forcing a username and password is a very realistic scenario, being able to compromise a user’s mutli-factor authentication setup can be quite difficult. Bypassing factors like app-based authorization, SMS verification, face ID, touch ID, etc., is a significantly more challenging than guessing a user’s password.&lt;/p&gt;

&lt;p&gt;Because of this, &lt;em&gt;a compromised JWT can actually be a greater security risk than a compromised username and password&lt;/em&gt;. Imagine the scenario above where the app a user logs into is protected by multi-factor authentication. Once the user logs in and verifies themselves via multi-factor, they are assigned a JWT to prove who they are. If that JWT is stolen, the attacker no longer needs to bypass MFA directly (like they would have to if they only had the user’s username and password)—they can now directly make requests as the user without additional identity proofing. Quite a big risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Do if Your JWT is Stolen
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IBuK3oXU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/what-do-i-do-d0f98ce43a73a34edca20f7d7f2a3f84bf2a1a47bb06e5fbb0d69b2b8b5762fa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IBuK3oXU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/what-do-i-do-d0f98ce43a73a34edca20f7d7f2a3f84bf2a1a47bb06e5fbb0d69b2b8b5762fa.jpg" alt="My JWT was stolen, what do I do?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once a JWT has been stolen, you’ll be in a bad situation: an attacker can now impersonate a client and access your service without the client’s consent. But, even though you’re in a bad situation, you’ve still got to make the most out of it.&lt;/p&gt;

&lt;p&gt;Here are a number of steps to take if a client’s token has been stolen. These recommendations are not suitable for every type of app, but should provide you with some good ideas to help you recover from this security incident:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Revoke compromised tokens immediately.&lt;/strong&gt; If you’re using a revocation list on your server to invalidate tokens, revoking a token can instantly boot the attacker out of your system until they get hold of a new token. While it is a temporary solution, it will make the attacker’s life slightly more difficult.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Force your client to change their password immediately.&lt;/strong&gt; In the context of a web or mobile app, force your user to reset their password immediately, preferably through some sort of multi-factor authentication flow like the ones &lt;a href="https://www.okta.com/products/adaptive-multi-factor-authentication/"&gt;Okta provides&lt;/a&gt;. Forcing a user to change their password can potentially keep attackers out of their account in the event that an attacker tries to use a compromised token to modify user login credentials. By requiring multi-factor authentication, you can have more confidence that the user resetting their credentials is who they say they are and not an attacker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect the client’s environment.&lt;/strong&gt; Was the user’s phone stolen so an attacker has access to their pre-authenticated mobile app? Was the client accessing your service from a compromised device like a mobile phone or infected computer? Discovering how the attacker got a hold of the token is the only way to fully understand what went wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect your server-side environment.&lt;/strong&gt; Was an attacker able to compromise the token from your end? If so, this might involve a lot more work to fix, but the earlier you get started the better.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve gone through these steps, you should hopefully have a better understanding of how the token was compromised and what needs to be done to prevent it from happening in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Detect Token Compromise
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--04huqZME--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/magnifying-glass-c3fc5120a04af94e5bc8a6ca3ab519c7a36a069aed0584c3bf04d27614099305.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--04huqZME--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://developer.okta.com/assets/blog/what-happens-if-your-jwt-is-stolen/magnifying-glass-c3fc5120a04af94e5bc8a6ca3ab519c7a36a069aed0584c3bf04d27614099305.jpg" alt="Magnifying glass"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When token compromise does happen, it can cause major problems. Particularly if you (as a service provider) aren’t able to quickly detect that an attacker has compromised a client’s token.&lt;/p&gt;

&lt;p&gt;What if you were able to automatically identify when a token was compromised? That would dramatically improve your service’s security, as you could proactively prevent suspicious requests from being fulfilled, thereby protecting your service and your users.&lt;/p&gt;

&lt;p&gt;While not easy, this is absolutely possible. Modern machine learning toolkits like &lt;a href="https://www.tensorflow.org/"&gt;TensorFlow&lt;/a&gt; allow you to build functional (although complex) pipelines to detect unusual patterns and proactively take charge of the situation.&lt;/p&gt;

&lt;p&gt;For example, you could use machine learning to detect unusual client locations. Let’s say you run a website, and your user has logged in from San Francisco and has been making requests for several hours. If you notice that requests start coming from a different geographical region a short time later, you can immediately prevent those requests from being fulfilled, revoke the tokens, and reach out to the user to reset their password, etc.&lt;/p&gt;

&lt;p&gt;In a similar manner, you could use machine learning to detect unusual client behavior. If a token is compromised, it’s likely that an attacker will take steps to abuse your service in some way. If you have a user who typically makes five requests per minute on your site, but all of a sudden you notice a massive uptick where the user is making 50+ requests per minute, that might be a good indicator that an attacker has gotten a hold of a user’s token, so you can revoke the tokens and reach out to the user to reset their password.&lt;/p&gt;

&lt;p&gt;Pattern detection and recognition through machine learning is a fantastic, modern way to handle some of these more complicated problems.&lt;/p&gt;

&lt;p&gt;This is precisely what we do here at &lt;a href="https://developer.okta.com/"&gt;Okta&lt;/a&gt; — we run an &lt;a href="https://developer.okta.com/signup/"&gt;API service&lt;/a&gt; that allows you to store user accounts in our service, and we provide developer libraries to handle things like authentication, authorization, social login, single sign-on, multi-factor authentication, etc. When users log into apps powered by Okta, we analyze a number of data points to detect if an account has been compromised, prompt for multi-factor authentication, perform user outreach, etc.&lt;/p&gt;

&lt;p&gt;There’s a lot of complexity involved in being proactive about your security, but it’s far better to be prepared than unprepared.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shameless Plug&lt;/strong&gt; : If you haven’t checked out our API service, it’s free to use and really fun! You can create an account here: &lt;a href="https://developer.okta.com/signup/"&gt;https://developer.okta.com/signup/&lt;/a&gt;. And… If you do happen to give it a go, I’d love to hear your thoughts, so please &lt;a href="mailto:randall.degges@okta.com"&gt;hit me up&lt;/a&gt; with any feedback about Okta, token authentication, or JSON Web Tokens. And finally, please &lt;a href="https://twitter.com/oktadev"&gt;follow @oktadev Twitter&lt;/a&gt; — we tweet about a lot of interesting security related topics like this.&lt;/p&gt;

&lt;p&gt;Happy hacking,&lt;/p&gt;

&lt;p&gt;-Randall&lt;/p&gt;


</description>
      <category>websecurity</category>
      <category>security</category>
      <category>jwt</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to Prevent Your Users from Using Breached Passwords</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Mon, 11 Jun 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/how-to-prevent-your-users-from-using-breached-passwords-5cne</link>
      <guid>https://dev.to/oktadev/how-to-prevent-your-users-from-using-breached-passwords-5cne</guid>
      <description>&lt;p&gt;Not too long ago, the National Institute of Standards and Technology (NIST) &lt;a href="https://www.nist.gov/itl/tig/projects/special-publication-800-63" rel="noopener noreferrer"&gt;officially recommended&lt;/a&gt; that user-provided passwords be checked against existing data breaches. Today I’m going to show you how you can easily add this functionality to any website you run using &lt;a href="https://github.com/OktaSecurityLabs/passprotect-js" rel="noopener noreferrer"&gt;PassProtect&lt;/a&gt;, an open-source developer library I created specifically for this purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Check User Passwords?
&lt;/h2&gt;

&lt;p&gt;The new &lt;a href="https://www.nist.gov/itl/tig/projects/special-publication-800-63" rel="noopener noreferrer"&gt;NIST recommendations&lt;/a&gt; mean that every time a user gives you a password, it’s your responsibility as a developer to check their password against a list of breached passwords and prevent the user from using a previously breached password.&lt;/p&gt;

&lt;p&gt;This is a big deal in the security community because for many years now, as more and more websites have been breached, attackers have started downloading the breached user credentials and using them to attempt to compromise accounts elsewhere.&lt;/p&gt;

&lt;p&gt;For instance, let’s say that your password, “fdsah35245!~!3”, was breached in the well-known &lt;a href="https://www.forbes.com/sites/josephsteinberg/2014/12/11/massive-security-breach-at-sony-heres-what-you-need-to-know/" rel="noopener noreferrer"&gt;Sony data breach&lt;/a&gt; back in 2014. Once those passwords were leaked, attackers would download the compromised passwords and use them to try to log into other user’s accounts.&lt;/p&gt;

&lt;p&gt;An attacker might, for example, try to log into user accounts using your leaked password because they know that this was a real password that someone was using, and the likelihood of other people using it is (you included) is high.&lt;/p&gt;

&lt;p&gt;To combat this, the officially recommended NIST solution is that you check each user-provided password to ensure it isn’t one of these leaked credentials — thereby reducing the odds that an attacker will be able to easily guess user credentials on your site.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Get Access to Breached Passwords
&lt;/h2&gt;

&lt;p&gt;The only problem with the NIST recommendation is that it is &lt;em&gt;hard to implement&lt;/em&gt;. In order to check a user’s password against a list of breached passwords you need to have a massive database of every set of leaked credentials. This is not only impractical, but a risk on many levels (security, legal, compliance).&lt;/p&gt;

&lt;p&gt;To help developers adopt this new NIST recommendation, &lt;a href="https://www.troyhunt.com/" rel="noopener noreferrer"&gt;Troy Hunt&lt;/a&gt; created the free service &lt;a href="https://haveibeenpwned.com/" rel="noopener noreferrer"&gt;Have I Been Pwned&lt;/a&gt; which aggregates all data breaches into a massive database.&lt;/p&gt;

&lt;p&gt;Have I Been Pwned allows you to access breached data by either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Downloading the breached data hashes directly: &lt;a href="https://haveibeenpwned.com/Passwords" rel="noopener noreferrer"&gt;https://haveibeenpwned.com/Passwords&lt;/a&gt; (scroll down on the page to find the download links), or&lt;/li&gt;
&lt;li&gt;Using the free and anonymous API: &lt;a href="https://haveibeenpwned.com/API/v2" rel="noopener noreferrer"&gt;https://haveibeenpwned.com/API/v2&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Have I Been Pwned API allows you to make as many requests as you want, which makes it particularly useful for checking to see if your users’ passwords have been breached.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Easily Check Your Users’ Passwords
&lt;/h2&gt;

&lt;p&gt;In order to make it easy for you to check your users’ passwords against the Have I Been Pwned database, I recently created the &lt;a href="https://github.com/OktaSecurityLabs/passprotect-js" rel="noopener noreferrer"&gt;passprotect-js&lt;/a&gt; developer library.&lt;/p&gt;

&lt;p&gt;It’s designed as a simple JavaScript library that can be dropped into any web page (anywhere on the page), that will check your users’ passwords against the Have I Been Pwned API service and inform the user if the password they’re using has been involved in a breach:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fshqq9xf3vgminovtawj1.gif" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fshqq9xf3vgminovtawj1.gif" alt="PassProtect Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PassProtect is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast&lt;/strong&gt; : the entire library is 16k (gzipped).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile friendly&lt;/strong&gt; : it renders great on devices of all sizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Informative&lt;/strong&gt; : it will explain to users that the password they’re attempting to use has been breached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not annoying&lt;/strong&gt; : it won’t repeatedly annoy the user about the same password over and over again in the current session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure&lt;/strong&gt; : no passwords are ever stored or shared over the network. PassProtect uses k-Anonymity which means that the only thing that is sent over the network are the first 5 characters of the password hash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To use PassProtect, all you need to do is drop the following &lt;code&gt;script&lt;/code&gt; tag somewhere into the pages on your site:&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;script src="https://cdn.passprotect.io/passprotect.min.js"&amp;gt;&amp;lt;/script&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;I hope that by providing some simple tooling we can help developers adopt the new NIST recommendations and promote better overall web security.&lt;/p&gt;

&lt;p&gt;Please &lt;a href="https://twitter.com/rdegges" rel="noopener noreferrer"&gt;hit me up&lt;/a&gt; if you have any questions or comments!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt; : If you’d like to enable PassProtect’s functionality on every single website you use, you can always go install the &lt;a href="https://chrome.google.com/webstore/detail/passprotect/cpimldclklpfifolmdnicjnfbjdepjnf" rel="noopener noreferrer"&gt;PassProtect Chrome extension&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And... If you like PassProtect, you might also like the Okta &lt;a href="https://developer.okta.com/" rel="noopener noreferrer"&gt;API service&lt;/a&gt;. The Okta API stores user accounts for the websites, mobile apps, and API services you’re building and makes it easy to handle things like authentication, authorization, etc. It has an awesome free plan for developers (like you), and you can create a new Okta account and give it a try here: &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;https://developer.okta.com/signup/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>security</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Static Sites vs CMS</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Thu, 07 Jun 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/static-sites-vs-cms-2bho</link>
      <guid>https://dev.to/oktadev/static-sites-vs-cms-2bho</guid>
      <description>&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%2Fstatic-sites%2Fnerd-fight-96c2a9c3b0743a460b0a6e1e329a910defb2ab4421f5ed529c28acfac31b30be.gif" 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%2Fstatic-sites%2Fnerd-fight-96c2a9c3b0743a460b0a6e1e329a910defb2ab4421f5ed529c28acfac31b30be.gif" alt="Nerd fight!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's a frequent debate amongst development and marketing teams at companies around the world about whether or not their blog or website should be managed through a content management system (CMS) like Wordpress, Drupal, Squarespace, etc. or through a static site generator like Jekyll or Hugo. I've been blogging since 2006, writing websites since 2002, and I've built just about every possible type of website. Today I'd like to explain why static sites are the superior choice in almost every possible circumstance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: This advice is specifically for web teams comprised of technical people (mainly developers). If your company doesn't have technical staff I still hope you'll find this information useful, but my advice may not apply.&lt;/p&gt;

&lt;p&gt;So, why are static sites the best?&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Fast
&lt;/h2&gt;

&lt;p&gt;There are no faster websites in the world than websites built using static site generators. This is a fact.&lt;/p&gt;

&lt;p&gt;The reason this is true is because dynamic websites, like those powered by Wordpress and Drupal, require that you (the site creator) have a web server running some code (PHP in this case), which responds to incoming web requests, then displays some content (a blog post, etc).&lt;/p&gt;

&lt;p&gt;This is a very &lt;strong&gt;slow&lt;/strong&gt; way of doing things, because it means that for each user who visits the site, the PHP code running behind the scenes need to start up, talk to a database, potentially talk to one (or more) caching servers, and execute a lot of logic before being able to render or display the page.&lt;/p&gt;

&lt;p&gt;When you use a static site generator like Jekyll or Hugo, however, these tools take your content (your articles, your HTML, etc.) and run some code &lt;strong&gt;once&lt;/strong&gt; to transform them into their final output formats: HTML, CSS, and JavaScript. This way, a visitor to your site is sent the static page files directly without any processing.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;much&lt;/strong&gt; faster and simpler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fun Fact&lt;/strong&gt;: &lt;em&gt;Googlebot and all of Google’s search ranking algorithms heavily favor fast websites over slow ones.&lt;/em&gt; When two sites have similar content, but one is faster: the faster one will usually have a higher page rank. See: &lt;a href="https://moz.com/blog/how-website-speed-actually-impacts-search-ranking" rel="noopener noreferrer"&gt;https://moz.com/blog/how-website-speed-actually-impacts-search-ranking&lt;/a&gt; for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Secure
&lt;/h2&gt;

&lt;p&gt;CMS systems (especially those built on PHP like Wordpress and Drupal) have abysmal security records. It can be incredibly difficult to maintain a CMS, keep it up-to-date, and constantly apply security patches to ensure it won't be easily abused by attackers. Unless you're an expert in the CMS and spend all your time managing it, security issues are bound to crop up.&lt;/p&gt;

&lt;p&gt;Google "Drupal hack" or "Wordpress hack" to see what I mean. Millions of Drupal and Wordpress sites are compromised &lt;em&gt;all the time&lt;/em&gt;. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.bbc.com/news/technology-29846539" rel="noopener noreferrer"&gt;Millions of Websites Hit by Drupal Hack (BBC)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thehackernews.com/2015/03/hacking-drupal-website.html" rel="noopener noreferrer"&gt;Drupal Patches Critical Password Reset Vulnerability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thehackernews.com/2014/11/drupal-sql-injection-vulnerability_2.html" rel="noopener noreferrer"&gt;Drupal SQL Injection Vulnerability Leave Millions of Websites Open to Hackers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.drupal.org/docs/develop/security/your-drupal-site-got-hacked-now-what" rel="noopener noreferrer"&gt;Your Drupal site got hacked. Now what?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://duckduckgo.com/?q=drupal+hack&amp;amp;atb=v18&amp;amp;ia=web" rel="noopener noreferrer"&gt;Etc...&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are hundreds of tools that anyone can easily download and run which attempt to compromise existing Wordpress and Drupal sites automatically, by trying all previously known vulnerabilities against the CMS systems, looking for holes.&lt;/p&gt;

&lt;p&gt;This is such a common occurrence that CMS systems like Wordpress and Drupal require specialized hosting systems to ensure this does not happen, and that the scope of security vulnerabilities (when discovered) are minimized as much as possible. The amount of maintenance required to keep a Wordpress / Drupal site secure is a job on its own.&lt;/p&gt;

&lt;p&gt;Static sites, on the other hand, are impossible to hack: there is no code running, and thus no vulnerabilities to exploit! For a security company like &lt;a href="https://developer.okta.com/" rel="noopener noreferrer"&gt;Okta&lt;/a&gt;, where security is fundamental to the company's mission and objective, this is a great benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Friendly for Developers
&lt;/h2&gt;

&lt;p&gt;At Okta, our developer documentation and blog are primarily written / edited / managed by a technical group of people. Using Git and Git tools are inherently native to the team. If your company's site is managed by a primarily technical audience, some subset of this may also be true.&lt;/p&gt;

&lt;p&gt;Static site generator tools are well known in the developer community at large. They carry a very positive reputation and almost everyone is familiar with them. Using one is a sign that an organization understands engineers and engineering problems, and is committed to providing quality user experiences.&lt;/p&gt;

&lt;p&gt;As web teams continue to scale out the amount of contributors / editors / staff that are working on web projects, sticking to the 80/20 rule is paramount: get 80% of the benefit with 20% of the work. Static site generators are the way to go here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are easy to understand for developers and non-technical users alike.&lt;/li&gt;
&lt;li&gt;With very minimal instruction ANYONE in the organization can contribute. There is a very low barrier to entry.&lt;/li&gt;
&lt;li&gt;They allow for much more controlled editorial than CMS systems do, something that is particularly important when writing technical content.&lt;/li&gt;
&lt;li&gt;They allow for more precise editing (eg: code blocks, technical project testing, etc.) These things are not easy to accomplish in CMS systems using their web editors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most developers enjoy working with static site generators, and are much happier using those than CMS systems.&lt;/p&gt;

&lt;p&gt;For more info: google "Drupal sucks" and "Wordpress sucks". Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.freelock.com/blog/john-locke/2011-10/top-6-reasons-drupal-really-sucks-developer-edition" rel="noopener noreferrer"&gt;Top 6 Reasons Drupal Sucks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@davide.borsatto/the-death-of-the-cms-cec078a0d1b9" rel="noopener noreferrer"&gt;The Death of the CMS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.slideshare.net/owenbrierley/why-i-hate-drupal-with-a-nod-to-james-wagner" rel="noopener noreferrer"&gt;Why I Hate Drupal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://duckduckgo.com/?q=drupal+sucks&amp;amp;atb=v18&amp;amp;ia=web" rel="noopener noreferrer"&gt;Etc…&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: Don’t even bother looking at &lt;a href="https://news.ycombinator.com/" rel="noopener noreferrer"&gt;HackerNews&lt;/a&gt; comments about Drupal. They're savage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites Provide Simple Permissioning
&lt;/h2&gt;

&lt;p&gt;CMS systems like Wordpress and Drupal have their own permission systems. You can create users, admins, and assign people certain types of privileges.&lt;/p&gt;

&lt;p&gt;This is also true regarding static site generators if they are built use Git and GitHub, which has a very sophisticated security model that allows very specific controls around who can do what, and when.  You can have project admins with unlimited powers, read-only editors who can submit suggested changes to articles pending review, and editors who can review and release changes to the website. Furthermore, most companies already use GitHub to manage employee access to projects, so this fits perfectly into existing workflows.&lt;/p&gt;

&lt;p&gt;This model works well in terms of editing privileges for any large editorial team. Furthermore, this process has been used successfully even for &lt;strong&gt;enormous&lt;/strong&gt; websites and teams. For instance: healthcare.gov (the website that powers all health plan selections and receives millions of visitors all the time) is built 100% with Jekyll with tremendous success: &lt;a href="https://developmentseed.org/blog/2013/10/24/its-called-jekyll/" rel="noopener noreferrer"&gt;https://developmentseed.org/blog/2013/10/24/its-called-jekyll/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fun Fact&lt;/strong&gt;: Remember how much backlash heathcare.gov got when it first came out? The main reason for the really poor initial launch was that they used a CMS system which was unable to withstand user demand and caused a majority of their issues. See: &lt;a href="http://www.newsweek.com/inside-healthcaregovs-failure-1449" rel="noopener noreferrer"&gt;http://www.newsweek.com/inside-healthcaregovs-failure-1449&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After saving the healthcare.gov project by switching to Jekyll, the new standards group inside the government team started rolling out Jekyll as a new standard for modern, secure, government websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Scalable
&lt;/h2&gt;

&lt;p&gt;Because websites and blogs are an important channel for any company, uptime, speed, and reliability are paramount.&lt;/p&gt;

&lt;p&gt;In this arena, static sites shine through above all other options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are infinitely scalable when hosted on Amazon (S3 + Cloudfront). Or, if you'd like a simpler solution: &lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;They can be easily deployed worldwide so that users in China see your website just as fast as a user in Kenya, or Tokyo, or California.&lt;/li&gt;
&lt;li&gt;They can be globally cached in an extremely simple way that requires no ongoing technical maintenance.&lt;/li&gt;
&lt;li&gt;They can be deployed and updated near-instantaneously, without delay.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above features are not always true of CMS systems (like Wordpress and Drupal). These systems often have caching plugins that must be used to handle higher visitor traffic, and these typically cause technical issues when you want to immediately deploy changes to a website, or recover from mistakes. Getting these working properly can be a very difficult job (we had tremendous issues with this at my previous company, and I've personally seen these issues cause problems at many other companies).&lt;/p&gt;

&lt;p&gt;Using CMS systems means that the database server which stores the content (web page content, article content, etc.) must also be highly available. These CMS systems use MySQL as their database and require not only web server scalability, but also database scalability, cache scalability, and other things. Doing a good job at scaling a CMS website is exponentially more difficult than doing so with a static site, which is designed for scale without any additional infrastructure, web servers, or work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Cheap
&lt;/h2&gt;

&lt;p&gt;Running a static site is inexpensive. For a site serving millions of visitors per month that is globally cached and is highly optimized for speed / availability: most companies would need to spend only a few dollars per month in hosting costs.&lt;/p&gt;

&lt;p&gt;Compare this to the cost of running a Drupal website, you would need to pay for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A company to host the site (this can easily cost thousands of dollars per month or more, for even small installations).&lt;/li&gt;
&lt;li&gt;Ongoing support / maintenance costs from contractors (this can be very expensive as well).&lt;/li&gt;
&lt;li&gt;Lots of time updating the system every few months, applying patches, taking backups, etc.&lt;/li&gt;
&lt;li&gt;Working with contractors to customize the behaviors of Drupal to make it suitable for team needs, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cost comparison is greatly in favor of static sites in every possible way. Static sites require less time, energy, manpower, and infrastructure cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Easy to Use
&lt;/h2&gt;

&lt;p&gt;In order to use a CMS system like Drupal to manage a website, blog, etc., there is a lot that each contributor needs to learn to be successful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to request / receive permissions to write / make changes.&lt;/li&gt;
&lt;li&gt;How to navigate through the UI and edit / create / manage articles / pages.&lt;/li&gt;
&lt;li&gt;How to insert code blocks and other special types of markup using the built-in web editors.&lt;/li&gt;
&lt;li&gt;How to publish articles, go through a review process, and preview articles.&lt;/li&gt;
&lt;li&gt;How to modify existing articles to fix issues, how to make suggested edits to other people's content / pages, etc.&lt;/li&gt;
&lt;li&gt;And many other things..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To successfully run a static site project, there is really almost nothing contributors need to know other than:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to open a text editor and write their article / content. (this is called markdown)&lt;/li&gt;
&lt;li&gt;What folder to store their article in. These folders are usually very easy to find (eg: &lt;code&gt;2017/my-article-name.md&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of needing to request / get permissions to the website, all someone needs to do is visit the website repository on GitHub, fork it, and then add whatever they want (this includes fixing other people's typos, grammar, etc. in a simple way). This can all be done in the web browser with limited technical knowledge required.&lt;/p&gt;

&lt;p&gt;Once someone has made changes to the website, they can create a pull request and an editor on the team will be immediately notified that someone has changes available, can review them, and then either merge them in or ask the contributor to make modifications. GitHub makes collaboration extremely easy.&lt;/p&gt;

&lt;p&gt;Static sites can be set up to automatically deploy user changes into a staging environment to make it easier for editors to review changes, and require zero command line knowledge to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites Provide Powerful Editorial
&lt;/h2&gt;

&lt;p&gt;There is no system more powerful for managing large projects and websites than Git and GitHub. The system is designed from the ground up to make collaborating with other project contributors as simple (and powerful) as possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can instantly review any past changes to a page, article, etc. Going back to the beginning of time.&lt;/li&gt;
&lt;li&gt;You can easily switch back and forth between changes, edits, etc. Making it possible to fix mistakes instantly and precisely.&lt;/li&gt;
&lt;li&gt;You never have to worry about things getting accidentally deleted or removed because Git holds onto these memories indefinitely.&lt;/li&gt;
&lt;li&gt;Anyone can get started contributing to the website without any prior permissions needed (they can add their changes, and submit them for review).&lt;/li&gt;
&lt;li&gt;Editors immediately are notified when a contributor want to make changes, and can instantly review their changes and either accept or reject them. This makes contributing extremely simple and painless for all parties.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compare this to the way CMS systems like Wordpress and Drupal manage editorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each contributor must be given access to the system (this is management overhead).&lt;/li&gt;
&lt;li&gt;Each contributor must be given special permissions so they know what they are allowed / not allowed to do.&lt;/li&gt;
&lt;li&gt;To have editorial notifications enabled, you must use special third party plugins.&lt;/li&gt;
&lt;li&gt;Edit history storage is not unlimited, and is very hard to switch out. EG: If someone edits an article incorrectly, and you want to "revert" their changes, it is a very large hassle.&lt;/li&gt;
&lt;li&gt;Edit history is limited, so if you delete something accidentally: this can be a massive issue. There may be no way to easily recover this information.&lt;/li&gt;
&lt;li&gt;Editing is done "inline": this means editors must modify content directly as opposed to in a separate state where changes can be tested / agreed upon by both parties.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you compare the two: it is clear that the Git workflow provides more control, safety, and ease of use for editorial for all parties involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Customizable
&lt;/h2&gt;

&lt;p&gt;Content management systems are massive programs. They are very complicated, and have many moving parts: the platforms get updated, plugins (first and third-party) get updated, and there are many areas that can be customized.&lt;/p&gt;

&lt;p&gt;Customizing CMSes can be an extremely time consuming, difficult, and error-prone task, even for experts.&lt;/p&gt;

&lt;p&gt;For instance: supporting developer-friendly web editors that output Markdown, handling custom permissions and workflows to accommodate editorial, and even managing theme files, stylesheets, and custom JavaScript code can become a very time consuming process.&lt;/p&gt;

&lt;p&gt;Compare this work with that of customizing a static site generator website: it is vastly simpler. Instead of having to have a contractor spend many hours tweaking things, team members can directly make changes they need, can easily review changes, merge them in, and roll out fixes.&lt;/p&gt;

&lt;p&gt;Using a static site generator also enables &lt;strong&gt;anyone&lt;/strong&gt; at your company to easily suggest or contribute changes to the website: style fixes, new components, etc. By enabling more people to easily get involved and contribute, you can greatly scale up output with very little effort. This would be impossible to do using a CMS system.&lt;/p&gt;

&lt;p&gt;Another huge part of customization is SEO. This is always a concern. For instance: having tools that can measure things like keyword density, ensure that titles are the correct length, ensure that meta description tags are the correct length, etc.&lt;/p&gt;

&lt;p&gt;These things are significantly more powerful using static sites as you can automate these items and codify rules around them. You don’t need to install third-party plugins and learn new flows: you can codify this behavior and instantly enforce it across the entire project.&lt;/p&gt;

&lt;p&gt;In regards to more advanced SEO editing (for instance, using HTML5 metadata which Google includes in their search algorithm rankings): a static site generator is your only choice. CMS systems like Wordpress and Drupal don’t support this level of customization at all (unless you're willing to manually edit each and every article's raw HTML), because you’re essentially controlling the output of the program directly. With static site generators, however, there are numerous ways to accomplish this, to ensure that things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dates are correctly formatted and marked up with HTML5.&lt;/li&gt;
&lt;li&gt;Time ranges are correctly formatted and marked up with HTML5.&lt;/li&gt;
&lt;li&gt;Assets that need to be preloaded or prefetched can be included to speed up rendering of complex code samples / media.&lt;/li&gt;
&lt;li&gt;Etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall: there is nothing more customizable / powerful than a static site generator for contributors or editors to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites Provide "Ownership"
&lt;/h2&gt;

&lt;p&gt;I strongly believe that owning core parts of your product leads to a good user experience.&lt;/p&gt;

&lt;p&gt;For instance: here at Okta, we are a security company. Because of this, we have an in-house security team which helps ensure Okta products are held to a higher standard. For our core IT dashboard service: we hire in-house engineers who spend their time and care carefully building quality products for Okta users.&lt;/p&gt;

&lt;p&gt;We would not outsource our core engineering team: and thus we should not outsource our technical blog and documentation, either.&lt;/p&gt;

&lt;p&gt;Because our blog (and developer docs) are critically important to our success, we should completely own and control this part of the product to ensure we can hold it up to extremely high quality standards.&lt;/p&gt;

&lt;p&gt;This is something that becomes vastly more difficult when a third-party company is managing our website, our CMS, and making changes and fixes to our web properties.&lt;/p&gt;

&lt;p&gt;Take a look at any outsourced products, and compare them to in-house products: with very few exceptions, in-house projects are almost always better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Portable
&lt;/h2&gt;

&lt;p&gt;CMS systems like Drupal and Wordpress store all content inside of a database, using very specific formatting. If your company ever decides to migrate to another platform in the future, migrating is a &lt;strong&gt;very&lt;/strong&gt; hard thing to do.&lt;/p&gt;

&lt;p&gt;This is because there is no easy way to export your data out of Drupal or Wordpress into a plain text format that can be easily imported into other systems.&lt;/p&gt;

&lt;p&gt;CMS systems like Wordpress / Drupal provide a lot of vendor lock in which makes porting your project to another system incredibly hard in the future.&lt;/p&gt;

&lt;p&gt;Compare this with static site generators like Jekyll and Hugo: your content is stored in its original format, without modification, forever. Moving from a static site generator to any other system is incredibly easy as there is no vendor lock in whatsoever. This gives you the flexibility in the future to shift to other systems with as little effort as technically possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites are Reliable
&lt;/h2&gt;

&lt;p&gt;One of the major reasons companies prefer static site generators is reliability. Using a static site generator like Jekyll or Hugo allows you do things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically test articles for broken URLs.&lt;/li&gt;
&lt;li&gt;Automatically find broken images and image links.&lt;/li&gt;
&lt;li&gt;Look for broken style rules and obvious UI errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Doing these things with a CMS system requires heavy customization and is very brittle.&lt;/p&gt;

&lt;p&gt;Using a static site generator gives your organization much more control over the quality of your edits and articles, because you can easily automate testing for them! This reduces the editor’s burden, as well as the burden of the team itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites vs CMS: A Summary
&lt;/h2&gt;

&lt;p&gt;Using a static site generator provides numerous benefits over what any CMS can provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are secure&lt;/li&gt;
&lt;li&gt;Developers enjoy using them&lt;/li&gt;
&lt;li&gt;They are fast&lt;/li&gt;
&lt;li&gt;The are easy to use even for those with minimal technical expertise&lt;/li&gt;
&lt;li&gt;They scale with 0 effort&lt;/li&gt;
&lt;li&gt;They cost exponentially less money to operate&lt;/li&gt;
&lt;li&gt;They require minimal maintenance effort&lt;/li&gt;
&lt;li&gt;They have a positive reputation in the developer community, and signify a strong engineering culture and team to outsiders&lt;/li&gt;
&lt;li&gt;They support more advanced, useful editorial than any CMS provides&lt;/li&gt;
&lt;li&gt;The enable anyone in the organization to contribute to the website, blog, documentation. You can leverage this to more easily expand contribution efforts.&lt;/li&gt;
&lt;li&gt;If you decide to move to another platform in the future, migrating away from a static site generator is &lt;em&gt;much&lt;/em&gt; easier than anything else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this post was helpful, you might really enjoy taking a look at our service, Okta: &lt;a href="https://dev.to/"&gt;https://developer.okta.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We're an API company that stores user accounts and handles things like authentication, authorization, social login, single sign-on, etc. It's easy to get started and we have an &lt;strong&gt;epic&lt;/strong&gt; free plan for developers (like you). If you want to give it a go, you can create a free account here: &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;https://developer.okta.com/signup/&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Announcing PassProtect - Proactive Web Security</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Wed, 23 May 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/announcing-passprotect---proactive-web-security-1d5c</link>
      <guid>https://dev.to/oktadev/announcing-passprotect---proactive-web-security-1d5c</guid>
      <description>&lt;p&gt;If you’re reading this article you probably care about web security. You probably use a password manager to manage your passwords, you’ve probably got &lt;a href="https://2fanotifier.org/" rel="noopener noreferrer"&gt;multi-factor authentication&lt;/a&gt; setup for all of your services, and you’re probably already subscribed to &lt;a href="https://haveibeenpwned.com/" rel="noopener noreferrer"&gt;Have I Been Pwned?&lt;/a&gt; so you’re alerted when one of your logins have been involved in a data breach.&lt;/p&gt;

&lt;p&gt;But &lt;em&gt;you’re&lt;/em&gt; not most people.&lt;/p&gt;

&lt;p&gt;Most web users are completely disconnected from the incredible advancements that have been made in the web security world over the last handful of years. Most web users aren’t notified when their credentials are leaked in a data breach, and to make matters worse, most users whose credentials &lt;em&gt;are&lt;/em&gt; breached never reset their passwords.&lt;/p&gt;

&lt;p&gt;Wouldn’t it be great if the websites that users visited every day could automatically notify users when the credentials they’re using are unsafe? This would give them the opportunity to change their unsafe passwords before attackers can take advantage of them. It would give them the knowledge they need to take the security of their personal information into their own hands.&lt;/p&gt;

&lt;p&gt;This is what our new developer library, &lt;a href="https://github.com/oktasecuritylabs/passprotect-js" rel="noopener noreferrer"&gt;PassProtect&lt;/a&gt;, enables.&lt;/p&gt;

&lt;p&gt;Instead of being the victim during a breach, PassProtect transforms even the most casual internet users into data security experts on par with you and I.&lt;/p&gt;

&lt;p&gt;The way PassProtect works is simple, by including a single JavaScript tag in your web pages, your users will instantly start getting notifications if the credentials they’ve entered on your site are unsafe.&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;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
    &amp;lt;script src="https://cdn.passprotect.io/passprotect.min.js"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do users see? An informative notification that gives them the information they need to make a good choice:&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%2Fpassprotect%2Fpassprotect-demo-33f7bbb6d8063f027318d16e4890d8285ca52950f8c393126c3ee80105dbc8e2.gif" 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%2Fpassprotect%2Fpassprotect-demo-33f7bbb6d8063f027318d16e4890d8285ca52950f8c393126c3ee80105dbc8e2.gif" alt="PassProtect Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PassProtect is built with casual users in mind, and provides simple but informative notifications. To avoid being annoying, PassProtect uses smart caching to ensure notifications are never repeated in a single session in any way that would hurt user experience.&lt;/p&gt;

&lt;p&gt;Furthermore, PassProtect piggybacks off the fabulous &lt;a href="https://haveibeenpwned.com/" rel="noopener noreferrer"&gt;Have I Been Pwned?&lt;/a&gt; service, the largest database of breached credentials on the internet (created by our friend, &lt;a href="https://www.troyhunt.com/" rel="noopener noreferrer"&gt;Troy Hunt&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;And because the data PassProtect works with is so sensitive (user passwords), we ensure that PassProtect never stores, collects, or send any password data over the network. Instead, PassProtect relies on &lt;a href="https://blog.cloudflare.com/validating-leaked-passwords-with-k-anonymity/" rel="noopener noreferrer"&gt;k-anonymity&lt;/a&gt; (created by our friends at Cloudflare), which just so happens to be the best way to verify that a password exists in a remote database without ever sending that password (or the full hash of that password) over a network. =)&lt;/p&gt;

&lt;p&gt;Don’t believe me? Check out &lt;a href="https://github.com/oktasecuritylabs/passprotect-js" rel="noopener noreferrer"&gt;the source&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This all sounds great, right!? The only problem is that our goal of dramatically improving the security of casual web users will only be realized if every developer embeds PassProtect in their websites. This is why I also went ahead and built a Chrome Extension for PassProtect as well. Firefox support will be coming soon.&lt;/p&gt;

&lt;p&gt;This way, web users who want to go ahead and take advantage of PassProtect directly can do so—this way &lt;em&gt;every&lt;/em&gt; website they visit will instantly inherit PassProtect’s functionality automatically!&lt;/p&gt;

&lt;p&gt;Nothing is truly secure. At some point or another, all systems will be subject to a vulnerability of some sort. Security will always be a cat-and-mouse game between attackers and defenders, and to win you need to hope for the best but prepare for the worst.&lt;/p&gt;

&lt;p&gt;We sincerely hope that PassProtect will help make the negatives (data breaches) a lot more positive by empowering individual users to reset their credentials when necessary and take charge of their personal data security.&lt;/p&gt;

&lt;p&gt;If you’d like to get PassProtect for your website, please check out our &lt;a href="https://github.com/oktasecuritylabs/passprotect-js" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt; (which contains far more information). If you’d like to use PassProtect in your browser, please check out our &lt;a href="https://chrome.google.com/webstore/detail/passprotect/cpimldclklpfifolmdnicjnfbjdepjnf" rel="noopener noreferrer"&gt;Chrome Extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Be safe out there! &amp;lt;3&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt; : If you’ve had a chance to play around with &lt;a href="https://www.passprotect.io" rel="noopener noreferrer"&gt;PassProtect&lt;/a&gt; please let me know what you think! Leave a comment down below or shoot me &lt;a href="//mailto:randall.degges@okta.com"&gt;an email&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>security</category>
    </item>
    <item>
      <title>Build a Video Chat Service with JavaScript, WebRTC, and Okta</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Thu, 10 May 2018 16:55:34 +0000</pubDate>
      <link>https://dev.to/oktadev/build-a-video-chat-service-with-javascript-webrtc-and-okta-22m0</link>
      <guid>https://dev.to/oktadev/build-a-video-chat-service-with-javascript-webrtc-and-okta-22m0</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'endcomment'&lt;/p&gt;
</description>
      <category>javascript</category>
      <category>webrtc</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Please Stop Using Local Storage</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Tue, 30 Jan 2018 05:03:48 +0000</pubDate>
      <link>https://dev.to/rdegges/please-stop-using-local-storage-1i04</link>
      <guid>https://dev.to/rdegges/please-stop-using-local-storage-1i04</guid>
      <description>&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fogcedxwio12syvr6wut2.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fogcedxwio12syvr6wut2.jpg" title="Grumpy Rage Face" alt="Grumpy Rage Face" width="350" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seriously. Just stop it already.&lt;/p&gt;

&lt;p&gt;I don't know what it is, exactly, that drives so many developers to store session information in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage" rel="noopener noreferrer"&gt;local storage&lt;/a&gt;, but whatever the reason: the practice needs to die out. Things are getting completely out of hand.&lt;/p&gt;

&lt;p&gt;Almost every day I stumble across a new website storing sensitive user information in local storage and it bothers me to know that so many developers are opening themselves up to catastrophic security issues by doing so.&lt;/p&gt;

&lt;p&gt;Let's have a heart-to-heart and talk about local storage and why you should stop using it to store session data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Local Storage?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F77aoiv7pjx5hypqya951.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F77aoiv7pjx5hypqya951.jpg" title="HTML5 Local Storage" alt="HTML5 Local Storage" width="500" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm sorry if I was a bit grumpy earlier. You don't deserve that! Heck, you might not even be familiar with what local storage is, let alone be using it to store your session information!&lt;/p&gt;

&lt;p&gt;Let's start with the basics: local storage is a new feature of HTML5 that basically allows you (a web developer) to store any information you want in your user's browser using JavaScript. Simple, right?&lt;/p&gt;

&lt;p&gt;In practice, local storage is just one big old JavaScript object that you can attach data to (or remove data from). Here's an example of some JavaScript code that stores some of my personal info in local storage, echoes it back to me, and then (optionally) removes it:&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;// You can store data in local storage using either syntax&lt;/span&gt;
&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rdegges&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;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;favoriteColor&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;black&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Once data is in localStorage, it'll stay there forever until it is&lt;/span&gt;
&lt;span class="c1"&gt;// explicitly removed&lt;/span&gt;
&lt;span class="nf"&gt;alert&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="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; really likes the color &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favoriteColor&lt;/span&gt; &lt;span class="o"&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="c1"&gt;// Removing data from local storage is also pretty easy. Uncomment the lines&lt;/span&gt;
&lt;span class="c1"&gt;// below to destroy the entries&lt;/span&gt;
&lt;span class="c1"&gt;//localStorage.removeItem("userName");&lt;/span&gt;
&lt;span class="c1"&gt;//localStorage.removeItem("favoriteColor");&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the JavaScript code above in your browser on a test HTML page, you'll see the phrase “rdegges really likes the color black.” in an alert message. If you then open up your developer tools, you'll be able to see the that both the &lt;code&gt;userName&lt;/code&gt; and &lt;code&gt;favoriteColor&lt;/code&gt; variables are both stored in local storage in your browser:&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%2Fwww.rdegges.com%2Fstatic%2Fimages%2F2018%2Flocal-storage-inspector.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%2Fwww.rdegges.com%2Fstatic%2Fimages%2F2018%2Flocal-storage-inspector.png" title="Local Storage Inspector" alt="Local Storage Inspector" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you might be wondering if there's some way to use local storage so that the data you store is automatically deleted at some point and you don't need to manually delete every single variable you put in there. Luckily, the HTML5 working group (shout out!) has your back. They added something called sessionStorage to HTML5 which works &lt;em&gt;exactly&lt;/em&gt; the same as local storage except that all data it stores is automatically deleted when the user closes their browser tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Cool About Local Storage?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvwyhfcn4ttyznvknhxk9.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvwyhfcn4ttyznvknhxk9.png" title="Happy Rage Face" alt="Happy Rage Face" width="350" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we're on the same page about what local storage is, let's talk about what makes it cool! Even though the whole point of this article is to dissuade you from using local storage to store session data, local storage still has some interesting properties.&lt;/p&gt;

&lt;p&gt;For one thing: it's pure JavaScript! One of the annoying things about cookies (the only real alternative to local storage) is that they need to be created by a web server. Boo! Web servers are boring and complex and hard to work with.&lt;/p&gt;

&lt;p&gt;If you're building a static site (like a single page app, for instance), using something like local storage means your web pages can run independently of any web server. They don't need any backend language or logic to store data in the browser: they can just do it as they please.&lt;/p&gt;

&lt;p&gt;This is a pretty powerful concept and one of the main reasons that local storage is such a hit with developers.&lt;/p&gt;

&lt;p&gt;Another neat thing about local storage is that it doesn't have as many size constraints as cookies. Local storage provides at least 5MB of data storage across all major web browsers, which is a heck of a lot more than the 4KB (maximum size) that you can store in a cookie.&lt;/p&gt;

&lt;p&gt;This makes local storage particularly useful if you want to cache some application data in the browser for later usage. Since 4KB (the cookie max size) isn't a lot, local storage is one of your only real alternative options.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Sucks About Local Storage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvp8ht3hahkpvfsd42r6w.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvp8ht3hahkpvfsd42r6w.png" title="Frowning Rage Face" alt="Frowning Rage Face" width="200" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK. We talked about the good, now let's spend a minute (or two!) talking about the bad.&lt;/p&gt;

&lt;p&gt;Local storage is soooo &lt;em&gt;basic&lt;/em&gt;. WHEW. I feel better already getting that off my chest. Local storage is just an incredibly basic, simple API.&lt;/p&gt;

&lt;p&gt;I feel like most developers don't realize just how basic local storage actually is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It can only store string data. Boo. This makes it pretty useless for storing data that's even slightly more complex than a simple string. And sure, you &lt;em&gt;could&lt;/em&gt; serialize everything including data types into local storage, but that's an ugly hack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It is synchronous. This means each local storage operation you run will be one-at-a-time. For complex applications this is a big no-no as it'll slow down your app's runtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It can't be used by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers" rel="noopener noreferrer"&gt;web workers&lt;/a&gt; =/ This means that if you want to build an application that takes advantage of background processing for performance, chrome extensions, things like that: you can't use local storage at all since it isn't available to the web workers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It still limits the size of data you can store (~5MB across all major browsers). This is a fairly low limit for people building apps that are data intensive or need to function offline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any JavaScript code on your page can access local storage: it has no data protection whatsoever. &lt;strong&gt;This is the big one for security reasons&lt;/strong&gt; (as well as my number one pet peeve in recent years).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To keep it short, here's the only situation in which you should use local storage: when you need to store some publicly available information that is not at all sensitive, doesn't need to be used in a high-performance app, isn't larger than 5MB, and consists of purely string data.&lt;/p&gt;

&lt;p&gt;If the app you're using doesn't fit the above description: &lt;em&gt;don't use local storage&lt;/em&gt;. Use something else (more on this later).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Local Storage is Insecure and You Shouldn't Use it to Store Sensitive Data
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwpj8oyxs3qhog709aa24.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwpj8oyxs3qhog709aa24.png" title="Stick Figure Instructor" alt="Stick Figure Instructor" width="400" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the deal: most of the bad things about local storage aren't all that important. You can still get away with using it but you'll just have a slightly slower app and minor developer annoyance. But security is different. The security model of local storage IS really important to know and understand since it will dramatically affect your website in ways you may not realize.&lt;/p&gt;

&lt;p&gt;And the thing about local storage is that it is &lt;em&gt;not secure&lt;/em&gt;! Not at all! Everyone who uses local storage to store sensitive information such as session data, user details, credit card info (even temporarily!) and anything else you wouldn't want publicly posted to Facebook is doing it wrong.&lt;/p&gt;

&lt;p&gt;Local storage &lt;em&gt;wasn't designed&lt;/em&gt; to be used as a secure storage mechanism in a browser. It was designed to be a simple string only key/value store that developers could use to build slightly more complex single page apps. That's it.&lt;/p&gt;

&lt;p&gt;What's the most dangerous thing in the entire world? That's right! JavaScript.&lt;/p&gt;

&lt;p&gt;Think about it like this: when you store sensitive information in local storage, you're essentially using the most dangerous thing in the world to store your most sensitive information in the worst vault ever created: not the best idea.&lt;/p&gt;

&lt;p&gt;What the problem really boils down to is cross-site scripting attacks (&lt;a href="https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)" rel="noopener noreferrer"&gt;XSS&lt;/a&gt;). I won't bore you with a full explanation of XSS, but here's the high level:&lt;/p&gt;

&lt;p&gt;If an attacker can run JavaScript on your website, they can retrieve all the data you've stored in local storage and send it off to their own domain. This means anything sensitive you've got in local storage (like a user's session data) can be compromised.&lt;/p&gt;

&lt;p&gt;Now, you might be thinking “So what? My website is secure. No attacker can run JavaScript on my website.”&lt;/p&gt;

&lt;p&gt;And that's a reasonable point. If your website is &lt;em&gt;truly&lt;/em&gt; secure and no attacker can run JavaScript code on your website then you are technically safe, but in reality that is incredibly hard to achieve. Let me explain.&lt;/p&gt;

&lt;p&gt;If your website contains &lt;em&gt;any&lt;/em&gt; third party JavaScript code included from a source outside your domain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Links to bootstrap&lt;/li&gt;
&lt;li&gt;Links to jQuery&lt;/li&gt;
&lt;li&gt;Links to Vue, React, Angular, etc.&lt;/li&gt;
&lt;li&gt;Links to any ad network code&lt;/li&gt;
&lt;li&gt;Links to Google Analytics&lt;/li&gt;
&lt;li&gt;Links to any tracking code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you are currently at risk for having an attacker run JavaScript on your website. Let's say your website has the following script tag embedded inside it:&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 &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://awesomejslibrary.com/minified.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, if awesomejslibrary.com is compromised and their &lt;code&gt;minified.js&lt;/code&gt; script gets altered to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loop through all data in local storage&lt;/li&gt;
&lt;li&gt;Send it to an API built to collect stolen information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... then you are completely screwed. In this situation the attacker would have easily been able to compromise anything you had stored in local storage and you would never notice. Not ideal.&lt;/p&gt;

&lt;p&gt;As engineers, I think we're frequently susceptible to thinking that we would never embed third-party JavaScript in our websites. But in the real world, this scenario rarely plays out.&lt;/p&gt;

&lt;p&gt;At most companies, the marketing team directly manages the public website using different WYSIWYG editors and tooling. Can you &lt;em&gt;really&lt;/em&gt; be sure that nowhere on your site are you using third-party JavaScript? I'd argue “no”.&lt;/p&gt;

&lt;p&gt;So to err on the side of caution and dramatically reduce your risk for a security incident: &lt;strong&gt;don't store anything sensitive in local storage&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  PSA: Don't Store JSON Web Tokens in Local Storage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7ejjtcb7tkcqa972q9gd.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7ejjtcb7tkcqa972q9gd.png" title="Stick Figure with Stop Sign" alt="Stick Figure with Stop Sign" width="200" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While I feel like I made myself clear that you should never &lt;em&gt;ever&lt;/em&gt; store sensitive information in local storage in the previous section, I feel the need to specifically call out JSON Web Tokens (JWTs).&lt;/p&gt;

&lt;p&gt;The biggest security offenders I see today are those of us who store JWTs (session data) in local storage. Many people don't realize that JWTs are essentially the same thing as a username/password.&lt;/p&gt;

&lt;p&gt;If an attacker can &lt;a href="https://stackoverflow.com/questions/34259248/what-if-jwt-is-stolen" rel="noopener noreferrer"&gt;get a copy of your JWT&lt;/a&gt;, they can make requests to the website on your behalf and you will never know. Treat your JWTs like you would a credit card number or password: don't ever store them in local storage.&lt;/p&gt;

&lt;p&gt;There are thousands of tutorials, YouTube videos, and even programming classes at universities and coding boot camps incorrectly teaching new developers to store JWTs in local storage as an authentication mechanism. &lt;strong&gt;THIS INFORMATION IS WRONG.&lt;/strong&gt; If you see someone telling you to do this, run away!&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Use Instead of Local Storage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft32tt3y6t9c321b23arh.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft32tt3y6t9c321b23arh.png" title="Pointing Man" alt="Pointing Man" width="300" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So with all of local storage's shortcomings, what should you use instead? Let's explore the alternatives!&lt;/p&gt;

&lt;h3&gt;
  
  
  Sensitive Data
&lt;/h3&gt;

&lt;p&gt;If you need to store sensitive data, you should always use a server-side session. Sensitive data includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User IDs&lt;/li&gt;
&lt;li&gt;Session IDs&lt;/li&gt;
&lt;li&gt;JWTs&lt;/li&gt;
&lt;li&gt;Personal information&lt;/li&gt;
&lt;li&gt;Credit card information&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;And anything else you wouldn't want to publicly share on Facebook&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need to store sensitive data, here's how to do it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When a user logs into your website, create a session identifier for them and store it in a cryptographically signed cookie. If you're using a web framework, look up “how to create a user session using cookies” and follow that guide.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure that whatever cookie library your web framework uses is setting the &lt;code&gt;httpOnly&lt;/code&gt; cookie flag. This flag makes it impossible for a browser to read any cookies, which is &lt;em&gt;required&lt;/em&gt; in order to safely use server-side sessions with cookies. Read &lt;a href="https://blog.codinghorror.com/protecting-your-cookies-httponly/" rel="noopener noreferrer"&gt;Jeff Atwood's article&lt;/a&gt; for more information. He's the &lt;em&gt;man&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure that your cookie library also sets the &lt;code&gt;SameSite=strict&lt;/code&gt; cookie flag (to prevent &lt;a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)" rel="noopener noreferrer"&gt;CSRF&lt;/a&gt; attacks), as well as the &lt;code&gt;secure=true&lt;/code&gt; flag (to ensure cookies can only be set over an encrypted connection).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Each time a user makes a request to your site, use their session ID (extracted from the cookie they send to you) to retrieve their account details from either a database or a cache (depending on how large your website is)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once you have the user's account info pulled up and verified, feel free to pull any associated sensitive data along with it&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern is simple, straightforward, and most importantly: &lt;em&gt;secure&lt;/em&gt;. And yes, you can most definitely scale up a large website using this pattern. Don't tell me that JWTs are “stateless” and “fast” and you have to use local storage to store them: you're wrong!&lt;/p&gt;

&lt;h3&gt;
  
  
  Non-String Data
&lt;/h3&gt;

&lt;p&gt;If you need to store data in the browser that isn't sensitive and isn't purely string data, the best option for you is IndexedDB. It's an API that lets you work with a database-esque object store in the browser.&lt;/p&gt;

&lt;p&gt;What's great about IndexedDB is that you can use it to store typed information: integers, floats, etc. You can also define primary keys, handle indexing, and create transactions to prevent data integrity issues.&lt;/p&gt;

&lt;p&gt;A great tutorial for learning about (and using) IndexedDB is this &lt;a href="https://developers.google.com/web/ilt/pwa/working-with-indexeddb" rel="noopener noreferrer"&gt;Google tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offline Data
&lt;/h3&gt;

&lt;p&gt;If you need your app to run offline, your best option is to use a combination of IndexedDB (above) along with the Cache API (which is a part of Service Workers).&lt;/p&gt;

&lt;p&gt;The Cache API allows you to cache network resources that your app needs to load.&lt;/p&gt;

&lt;p&gt;A great tutorial for learning about (and using) the Cache API is this &lt;a href="https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/cache-api" rel="noopener noreferrer"&gt;Google tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Please Stop Using Local Storage
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvwyhfcn4ttyznvknhxk9.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvwyhfcn4ttyznvknhxk9.png" title="Happy Rage Face" alt="Happy Rage Face" width="350" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we've had a chance to talk about local storage, I hope you understand why you (probably) shouldn't be using it.&lt;/p&gt;

&lt;p&gt;Unless you need to store publicly available information that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is not at all sensitive&lt;/li&gt;
&lt;li&gt;Doesn't need to be used in an ultra high performance app&lt;/li&gt;
&lt;li&gt;Isn't larger than 5MB&lt;/li&gt;
&lt;li&gt;Consists of purely string data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;... &lt;strong&gt;don't use local storage!&lt;/strong&gt; Use the right tool for the job.&lt;/p&gt;

&lt;p&gt;And please, please, whatever you do, do not store session information (like JSON Web Tokens) in local storage. This is a very bad idea and will open you up to an extremely wide array of attacks that could absolutely cripple your users.&lt;/p&gt;

&lt;p&gt;Have a question? &lt;a href="//mailto:r@rdegges.com"&gt;Shoot me an email&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Stay safe out there =)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: For those of you who made it this far who are wondering why I didn't specifically call out &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP" rel="noopener noreferrer"&gt;Content Security Policy&lt;/a&gt; as a way to mitigate the effects of XSS, I specifically chose not to include this because it cannot help in the situation I described above. Even if you use CSP to whitelist all third-party JavaScript domains, that does nothing to prevent XSS if the third party provider is compromised.&lt;/p&gt;

&lt;p&gt;And while we're at it: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity" rel="noopener noreferrer"&gt;subresource integrity&lt;/a&gt; (while cool) is also not a global solution to this issue. For most marketing tools, ad networks, etc. (which are by far the most commonly used types of third-party JavaScript), subresource integrity is almost never used as the providers of those scripts &lt;em&gt;want&lt;/em&gt; to change them frequently so they can silently update functionality for their users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: I'm not the only one who thinks you should never store anything sensitive in local storage. So does &lt;a href="https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Local_Storage" rel="noopener noreferrer"&gt;OWASP&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;... In other words, any authentication your application requires can be bypassed by a user with local privileges to the machine on which the data is stored. Therefore, it's recommended not to store any sensitive information in local storage.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>programming</category>
      <category>security</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build Your Own Invoicing Service with Node, Coinbase, Bitcoin, and Okta</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Thu, 25 Jan 2018 10:08:41 +0000</pubDate>
      <link>https://dev.to/oktadev/build-your-own-invoicing-service-with-node-coinbase-bitcoin-and-okta-55la</link>
      <guid>https://dev.to/oktadev/build-your-own-invoicing-service-with-node-coinbase-bitcoin-and-okta-55la</guid>
      <description>&lt;p&gt;I got into Bitcoin back in 2011. Since then, I've been a fan of cryptocurrencies and have always had an interest in them. I've also built several Bitcoin projects over the years (an information website, an e-commerce site, and several others) to help promote the usage of the cryptocurrency (while having some fun).&lt;/p&gt;

&lt;p&gt;The idea of being able to send and receive money almost instantly from anywhere in the world with no middleman is really appealing to a lot of people.&lt;/p&gt;

&lt;p&gt;Today, I thought it'd be fun to build a small web invoicing portal (something similar to &lt;a href="https://www.freshbooks.com/" rel="noopener noreferrer"&gt;FreshBooks&lt;/a&gt;, but much less sophisticated) that allows you to easily invoice your clients over email and collect payment in Bitcoin.&lt;/p&gt;

&lt;p&gt;The client can then pay their invoices using their local currency or Bitcoin (if they have it). In the end: you'll be able to manage and bill your clients and receive payment in Bitcoin.&lt;/p&gt;

&lt;p&gt;I do a bit of consulting work myself and will be using this in the future. =)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PS&lt;/strong&gt;: If you want to skip the article and go &lt;a href="https://github.com/oktadeveloper/crypto-invoicer" rel="noopener noreferrer"&gt;straight to the code&lt;/a&gt;, go for it! I'm using Node.js, Express.js, and &lt;a href="https://www.coinbase.com" rel="noopener noreferrer"&gt;Coinbase&lt;/a&gt; to power the application.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fohv1bfvtbdpxat7g50sj.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fohv1bfvtbdpxat7g50sj.png" alt="Crypto Invoicer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started with Coinbase, Okta, and Node.js
&lt;/h2&gt;

&lt;p&gt;Before I walk you through building the application, there are a few things you'll need to do.&lt;/p&gt;

&lt;p&gt;You'll need to go create an account with &lt;a href="https://www.coinbase.com/join/51660a68c08669f6b8000046" rel="noopener noreferrer"&gt;Coinbase&lt;/a&gt;. Coinbase is the largest and most popular Bitcoin exchange in the US. It allows you to easily get started using Bitcoin without needing to install software, learn a lot, etc.&lt;/p&gt;

&lt;p&gt;You'll also need to create an &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;Okta developer account&lt;/a&gt;. Okta is an API service that allows you to create user accounts, and perform simple authentication and authorization for your web apps, mobile apps, and API services.&lt;/p&gt;

&lt;p&gt;Finally, you'll need to have Node.js setup on your computer and be ready to do some coding! &amp;gt;:)&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Up Coinbase
&lt;/h3&gt;

&lt;p&gt;To send invoices and request money from different clients you might be consulting for, you'll need to first generate a Coinbase API key with the proper permissions.&lt;/p&gt;

&lt;p&gt;Coinbase has an expansive API that you can use to do a number of things: one of which is &lt;a href="https://developers.coinbase.com/api/v2#request-bitcoin" rel="noopener noreferrer"&gt;send invoices requesting money&lt;/a&gt;.&lt;br&gt;
To do this, you'll need to visit the Coinbase &lt;a href="https://www.coinbase.com/settings/api" rel="noopener noreferrer"&gt;API management page&lt;/a&gt;, then click the button to create a new API key.&lt;/p&gt;

&lt;p&gt;When you see the popup modal that prompts you for permissions, use the settings below:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8jhexywtg9wywipsbh7u.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8jhexywtg9wywipsbh7u.png" alt="Coinbase API Key Options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you're doing here is requesting API permission to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View your different Coinbase accounts (wallet:accounts:read)&lt;/li&gt;
&lt;li&gt;View any past transactions you've made (wallet:transactions:read)&lt;/li&gt;
&lt;li&gt;Create new transactions to request money (wallet:transactions:request)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you've finished creating the key, you'll be able to see an API key and API secret value. &lt;strong&gt;Copy these down, you'll need them later.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Set Up Okta
&lt;/h3&gt;

&lt;p&gt;Now that your Coinbase account is ready for usage, you need to set up your Okta account. This is what you'll be using to protect your portal so only you can access it.&lt;/p&gt;

&lt;p&gt;Log into your Okta dashboard and copy down the &lt;strong&gt;Org URL&lt;/strong&gt; value you see at the top right of the page. &lt;strong&gt;You will need this value later.&lt;/strong&gt; It looks something like this:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjtt58jj9c5s9e57ma60i.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fjtt58jj9c5s9e57ma60i.png" alt="Okta Org URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You next need to create a new Okta Application. Using Okta, you can manage users for many applications you might have.&lt;/p&gt;

&lt;p&gt;To do this, click the large Applications menu item and click Add Application. Then when you are prompted, select the &lt;strong&gt;Web&lt;/strong&gt; application option. This tells Okta that you are building a web application (not an API service, for instance). Behind the scenes, Okta uses this information to set your app up with the proper types of OAuth 2.0 and OpenID Connect.&lt;/p&gt;

&lt;p&gt;Now you'll see a page asking you to define your Application settings. Use the values below:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh96ht8do0y1prp6pijlp.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fh96ht8do0y1prp6pijlp.png" alt="Okta Create App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These settings basically tell Okta where your web app will be running (locally in this example) and what sort of security rules to apply.&lt;/p&gt;

&lt;p&gt;Once you've finished creating the Application, you'll then be taken to your settings page for this newly created Application. You'll want to copy down two values, your &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt;. &lt;strong&gt;These will be needed later.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcifqj8fu1d5pph0iqvmq.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcifqj8fu1d5pph0iqvmq.png" alt="Okta App Credentials"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These credentials will be used to communicate securely with Okta in order to authenticate yourself into the web portal later.&lt;/p&gt;
&lt;h2&gt;
  
  
  Clone the Project
&lt;/h2&gt;

&lt;p&gt;Now that we've done the boring stuff, let's take a look at some code.&lt;/p&gt;

&lt;p&gt;You can either clone the project locally from my GitHub repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git clone https://github.com/oktadeveloper/crypto-invoicer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can &lt;a href="https://github.com/oktadeveloper/crypto-invoicer" rel="noopener noreferrer"&gt;fork the project&lt;/a&gt; to your own GitHub account and then clone that locally. This might make it easier to make changes and play around with the code as you follow along below.&lt;/p&gt;

&lt;p&gt;Through the rest of this article, I'll assume that you're working inside of the cloned/forked project directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Your Credentials
&lt;/h2&gt;

&lt;p&gt;Now let's take the credentials you gathered earlier and define them as environment variables that you'll use to store these sensitive values.&lt;/p&gt;

&lt;p&gt;To do this, you'll want to create a file named &lt;code&gt;.env&lt;/code&gt; which looks like 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;# .env
export OKTA_ISSUER_URI=https://xxx/oauth2/default
export OKTA_CLIENT_ID=xxx
export OKTA_CLIENT_SECRET=xxx
export REDIRECT_URI=http://localhost:3000/authorization-code/callback
export PORT=3000
export SECRET=xxx
export COINBASE_APIKEY_ID=xxx
export COINBASE_APIKEY_SECRET=xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Substitute your credentials where you see the &lt;code&gt;xxx&lt;/code&gt; placeholder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OKTA_ISSUER_URI&lt;/code&gt; should be set to the value of the &lt;strong&gt;Org URL&lt;/strong&gt; value you copied down earlier, and placed into the URL. The final URL should look something like &lt;code&gt;https://dev-111464.oktapreview.com/oauth2/default&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OKTA_CLIENT_ID&lt;/code&gt; and &lt;code&gt;OKTA_CLIENT_SECRET&lt;/code&gt; are the Application credentials you generated when you created your Okta Application previously&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REDIRECT_URI&lt;/code&gt; is a hard-coded URL that will be used as part of the authentication flow. More on this later.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PORT&lt;/code&gt; is the HTTP port you'll be running your webserver on. &lt;code&gt;3000&lt;/code&gt; is standard for Node.js apps&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SECRET&lt;/code&gt; should be a long, random string you define. This is used to secure your HTTP sessions and keep your authentication data safe. I like to generate these by bashing my hands on the keyboard for a second or two.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COINBASE_APIKEY_ID&lt;/code&gt; and &lt;code&gt;COINBASE_APIKEY_SECRET&lt;/code&gt; are your Coinbase API credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have these settings defined, you'll need to tell your terminal to &lt;em&gt;use&lt;/em&gt; these variables. To do this, if you're using a standard Linux/Mac/BSD terminal, you can run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ source .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;source&lt;/code&gt; command will tell your shell to take the variables defined in this file and make them available to the terminal for usage in your programs later on.&lt;/p&gt;

&lt;p&gt;If you're using Windows, you'll need to &lt;a href="https://technet.microsoft.com/en-us/library/ff730964.aspx" rel="noopener noreferrer"&gt;do something different&lt;/a&gt;. Sorry!&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Dependencies
&lt;/h2&gt;

&lt;p&gt;Now that the setup is completely finished, install all of the project dependencies using &lt;code&gt;npm&lt;/code&gt;, the Node.js package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will install all of the dependent packages by analyzing the &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; file in the project directory.&lt;/p&gt;

&lt;p&gt;Among these dependencies, there are a few interesting ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://expressjs.com/" rel="noopener noreferrer"&gt;express&lt;/a&gt; is the web framework you'll use to build the app&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/coinbase/coinbase-node" rel="noopener noreferrer"&gt;coinbase-node&lt;/a&gt; is the officially supported Coinbase developer library you'll be using to interact with the Coinbase API&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/oidc-middleware" rel="noopener noreferrer"&gt;oidc-middleware&lt;/a&gt; is a popular OpenID Connect middleware maintained by Okta that handles user authentication and authorization for Node.js apps&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build the Frontend
&lt;/h2&gt;

&lt;p&gt;Fair warning: I'm not a great frontend developer. I'm more of a server-side developer.&lt;/p&gt;

&lt;p&gt;The first thing I like to do when starting new projects is quickly define the frontend views. This part is more difficult for me, so I like to get it out of the way upfront.&lt;/p&gt;

&lt;p&gt;If you take a look at the &lt;code&gt;views&lt;/code&gt; directory, you'll notice that there are only three files: &lt;code&gt;base.pug&lt;/code&gt;, &lt;code&gt;index.pug&lt;/code&gt;, and &lt;code&gt;dashboard.pug&lt;/code&gt;. These three views render the entire website.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;base.pug&lt;/code&gt; is a shared base template that the other two templates extend. More on this in a moment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;index.html&lt;/code&gt; is the home page of the site&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dashboard.pug&lt;/code&gt; is the site's dashboard view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've defined these HTML views using the &lt;a href="https://pugjs.org/api/getting-started.html" rel="noopener noreferrer"&gt;pug&lt;/a&gt; templating language. This lets you write HTML without all the closing tags and allows you to use whitespace to infer structure.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;base.pug&lt;/code&gt; template provides some common HTML that the other two views extend. This prevents you from needing to duplicate HTML that is shared between one or more pages.&lt;/p&gt;

&lt;p&gt;Here's what the &lt;code&gt;base.pug&lt;/code&gt; template looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;doctype html
html(lang="en")
  head
    &amp;lt;!-- Required meta tags --&amp;gt;
    meta(charset="utf-8")
    meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no")

    &amp;lt;!-- Bootstrap CSS --&amp;gt;
    link(rel="stylesheet", href="https://bootswatch.com/4/sketchy/bootstrap.min.css")
    link(rel="stylesheet", href="/static/css/style.css")

  body
    .container
      block body

    &amp;lt;!-- Optional JavaScript --&amp;gt;
    &amp;lt;!-- jQuery first, then Popper.js, then Bootstrap JS --&amp;gt;
    script(src="https://code.jquery.com/jquery-3.2.1.slim.min.js", integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN", crossorigin="anonymous")
    script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js", integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh", crossorigin="anonymous")
    script(src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js", integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ", crossorigin="anonymous")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a pretty standard HTML page that uses the &lt;a href="http://getbootstrap.com/" rel="noopener noreferrer"&gt;Bootstrap&lt;/a&gt; CSS library with the &lt;a href="https://bootswatch.com/sketchy/" rel="noopener noreferrer"&gt;Sketchy&lt;/a&gt; Bootswatch theme. This theme makes the entire site look like a mockup. Since this is an example application, I thought the theme was fitting.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;index.pug&lt;/code&gt; view is also quite simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends base.pug

block body
  h1.text-center.head Crypto Invoicer

  .row.intro
    .col
    .col-8
      .jumbotron
        h2.text-center A Personal Invoicing Portal

        p.
          This is a personal invoicing portal. Use this portal to bill your clients
          for work done using #[a(href="https://www.coinbase.com/") Coinbase]:
          accept money in USD or Bitcoin.

        p.
          If you're performing work for clients and need a simple way to bill
              them, give Crypto Invoicer a try!

        p.
          Please #[a.btn.btn-primary(href="/login") login] to continue.
    .col
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This template simply displays a basic home page that prompts the user to log into their account to continue:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqd9whew1b67tbpi9263l.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqd9whew1b67tbpi9263l.png" alt="Crypto Invoicer 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last view you need to inspect is the &lt;code&gt;dashboard.pug&lt;/code&gt; view. This view renders the dashboard page that allows a user to create and view their invoices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extends base.pug

block body
  script(src="/static/js/sorttable.js")

  ul.nav.nav-pills.justify-content-end
    li.nav-item
      a.nav-link.active(href="/") Home
      li.nav-item
        a.nav-link.active(href="/logout") Logout

  h1.text-center Dashboard

  h2.create-invoice Create Invoice
  .row
    .col
    .col-6
      .jumbotron
        if error
          p.error #{error}

        form.form(method="post")
          .form-group
            label(for="email") To
            input#email.form-control(type="email", placeholder="Client Email", name="email", required=true)
          .form-group
            label(for="description") Description
            input#description.form-control(type="text", placeholder="Description", name="description", required=true)
          .form-group
            label(for="amount") Amount (USD)
            input#amount.form-control(type="number", min="1", step="any", name="amount", required=true)
          button.btn.btn-primary(type="submit") Create Invoice

    .col

  if transactions
    h2 Invoices
    table.table.sortable
      thead.thead-dark
        tr
          td Invoice #
          td Date Created
          td Completed?
          td Client Email
          td Description
          td Amount (USD)
      tbody
        each transaction in transactions
          tr
            td #{transaction.id}
            td #{new Date(transaction.created_at).toLocaleDateString("en-US", { hour12: false, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" })}
            td #{transaction.status}
            td #{transaction.to.email}
            td #{transaction.description}
            td $#{transaction.native_amount.amount}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This page is a bit more complex. It does a few key things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It creates a form that allows the user to send a client an invoice. This form takes a few input parameters: the client's email address, a description of what is being billed, and finally an amount (in USD) to bill the client.&lt;/li&gt;
&lt;li&gt;It lists all past invoices in an HTML table that can be sorted with JavaScript. To do this, you'll use pug to loop through all past transaction objects, and display their data as appropriate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you render this page, you'll see the invoice creation form:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc504najlify2qa2gq67o.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc504najlify2qa2gq67o.png" alt="Crypto Invoicer Form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And… If you've generated any past invoices, you'll see them listed below:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbbypnso0kj2yz8u5cz9y.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbbypnso0kj2yz8u5cz9y.png" alt="Crypto Invoicer List"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll also notice that if you click one of the table headers, you're able to sort all of the invoices by any column you want.&lt;/p&gt;

&lt;p&gt;If you take a look at the &lt;code&gt;dashboard.pug&lt;/code&gt; template code above, you can see how this works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://kryogenix.org/code/browser/sorttable/" rel="noopener noreferrer"&gt;sorttable&lt;/a&gt; JavaScript library is used to provide automatic table sorting in the browser&lt;/li&gt;
&lt;li&gt;Pug is being used to display transaction details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other than these two things, the rest of the page is plain old HTML. Nothing fancy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the Server
&lt;/h2&gt;

&lt;p&gt;Now that you've seen how the frontend code works, let's take a look at the server-side codebase.&lt;/p&gt;

&lt;p&gt;Open up the &lt;code&gt;server.js&lt;/code&gt; file found in the root of the project folder and follow along below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Import Dependencies
&lt;/h3&gt;

&lt;p&gt;The first thing I do in the &lt;code&gt;server.js&lt;/code&gt; is import all the Node.js dependencies needed to run the app:&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;use strict&lt;/span&gt;&lt;span class="dl"&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;Client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;coinbase&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&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;async&lt;/span&gt;&lt;span class="dl"&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;bodyParser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&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;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express-session&lt;/span&gt;&lt;span class="dl"&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;ExpressOIDC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@okta/oidc-middleware&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ExpressOIDC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing special here! Importing dependencies is standard in just about every app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define Globals
&lt;/h3&gt;

&lt;p&gt;The next thing you'll notice in &lt;code&gt;server.js&lt;/code&gt; is a section of code that defines a number of global variables:&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;// Globals&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OKTA_ISSUER_URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OKTA_ISSUER_URI&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;OKTA_CLIENT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OKTA_CLIENT_ID&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;OKTA_CLIENT_SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OKTA_CLIENT_SECRET&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;REDIRECT_URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3000&lt;/span&gt;&lt;span class="dl"&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;SECRET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECRET&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;client&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;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COINBASE_APIKEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COINBASE_APIKEY_SECRET&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the &lt;code&gt;const&lt;/code&gt; definitions are fairly straightforward: they pull in the environment variable values that were set previously, and store them as JavaScript variables so they can be easily referenced.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;client&lt;/code&gt; variable defines a new Coinbase API client (which is later used to talk to the Coinbase API).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;account&lt;/code&gt; variable represents a Coinbase Account object. In Coinbase you can have any number of "Accounts": Bitcoin wallets, USD wallets, etc. You can move money between these much like checking accounts at a normal bank. When implementing the invoicing later, you'll need to know which Coinbase Account you want to issue the request for, this determines how you receive the money.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;transactions&lt;/code&gt; variable will be our own in-memory cache of all recent invoice transactions available to us via the Coinbase API. This is what we'll use when rendering our dashboard page later on: we'll store a cache of the transactions to avoid making API calls to Coinbase on each page load.&lt;/p&gt;

&lt;p&gt;Finally, you'll notice the &lt;code&gt;app&lt;/code&gt; variable. This is a standard Express.js convention: create an &lt;code&gt;app&lt;/code&gt; object and use that to start up the web server later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure App Settings and Middleware
&lt;/h3&gt;

&lt;p&gt;Once the globals have been defined, the next thing you need to do is define the app settings and middleware.&lt;/p&gt;

&lt;p&gt;There's a section of code commented that contains these two blocks of functionality:&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;// App settings&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;view engine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// App middleware&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/static&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;static&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;httpOnly&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="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SECRET&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="c1"&gt;// Authentication&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;oidc&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;ExpressOIDC&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OKTA_ISSUER_URI&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;OKTA_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OKTA_CLIENT_SECRET&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;REDIRECT_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;defaultRedirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard&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;scope&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 profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's only one actual app setting here: &lt;code&gt;app.set("view engine", "pug");&lt;/code&gt;, and all it does is tell Express to use the pug templating engine when rendering views.&lt;/p&gt;

&lt;p&gt;Below that are the middleware definitions.&lt;/p&gt;

&lt;p&gt;The first middleware defined is &lt;code&gt;express.static&lt;/code&gt;. This middleware is configured to serve static assets (css, images, javascript) from the &lt;code&gt;static&lt;/code&gt; directory in the root of the project folder. This definition tells Express that any requests that start with &lt;code&gt;/static&lt;/code&gt; should be routed to that folder, and automatically return whatever files exist there.&lt;/p&gt;

&lt;p&gt;This might be a good time to inspect the &lt;code&gt;static&lt;/code&gt; folder and see what's in it. There are only two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;style.css&lt;/code&gt; file which holds some custom styling, and&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;sorttable.js&lt;/code&gt; script which is used in our frontend to make our HTML table sortable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next you'll see the express-session middleware defined. What this middleware does is configure Express to store sensitive user information in cookies (which are the safest way to store authentication data). When you are logged into the website via Okta later on, your authentication information will be stored in these cookies that are managed by this library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: The &lt;code&gt;SECRET&lt;/code&gt; variable that's used when initializing the session library is incredibly important. This long, random string that you previously defined is what keeps your cookies safe from tampering. If this value is ever leaked publicly (on GitHub, etc.) it would be a security catastrophe. All cookie-based systems require a secret key to be used to cryptographically validate the cookie.&lt;/p&gt;

&lt;p&gt;The last middleware you'll see is the &lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/oidc-middleware" rel="noopener noreferrer"&gt;oidc-middleware&lt;/a&gt;. This is a little more complex, as it handles a lot of magic behind the scenes, and makes all the authentication logic in the application work.&lt;/p&gt;

&lt;p&gt;The way this middleware works is by fully enabling your app to use OpenID Connect (OIDC) for authentication. When you define the new &lt;code&gt;ExpressOIDC&lt;/code&gt; and give it your Okta configuration information, it builds an OIDC object that remembers all your application rules: what URL your application runs one, where to redirect the user after they've logged in, what your secret application keys are, etc.&lt;/p&gt;

&lt;p&gt;Once this new object is created, it contains an Express router object that is then enabled below with the &lt;code&gt;app.use(oidc.router);&lt;/code&gt; call. This line registers some magical routes behind the scenes: the main one of which is &lt;code&gt;/login&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When this line of code is executed any requests to &lt;code&gt;/login&lt;/code&gt; will redirect you to your dedicated login page (hosted by Okta), and prompt you to log into the application. Once the user has been logged in, they will then be redirected BACK to your Node.js application, where they will be logged in and able to access the dashboard page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define Helpers
&lt;/h3&gt;

&lt;p&gt;Let's skip towards the bottom of the &lt;code&gt;server.js&lt;/code&gt; file now and take a look at the &lt;code&gt;updateTransactions&lt;/code&gt; function:&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;// Helpers&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateTransactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pagination&lt;/span&gt; &lt;span class="o"&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;async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;doWhilst&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;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pagination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nx"&gt;pagination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next_uri&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="nx"&gt;txns&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;txn&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;txn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;request&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="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;txn&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="nf"&gt;callback&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;function&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="nx"&gt;pagination&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="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="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;cb&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="nx"&gt;transactions&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The purpose of this helper function is to build an in-memory cache of Coinbase transactions.&lt;/p&gt;

&lt;p&gt;Each time you request money from a client and send them an invoice, Coinbase creates a transactional record. There are many different types of transactions that Coinbase logs, so what this function does is iterate through &lt;em&gt;all&lt;/em&gt; available transactions, pruning out just the ones relevant to invoicing, then stores them in the global &lt;code&gt;transactions&lt;/code&gt; array variable for later usage.&lt;/p&gt;

&lt;p&gt;The idea here is that each time the dashboard is displayed, instead of talking to the Coinbase API and performing this logic in real-time, the app will simply pull the latest list of transactions out of the cache instead.&lt;/p&gt;

&lt;p&gt;In this function I'm using the &lt;a href="http://caolan.github.io/async/" rel="noopener noreferrer"&gt;async&lt;/a&gt; library to perform a do-while loop that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Talks to the Coinbase API and requests a list of transactions&lt;/li&gt;
&lt;li&gt;Tries to determine whether there are any more "pages" of transactions left to iterate through (because there may be many transactions, it might require many requests to the Coinbase API to retrieve them all)&lt;/li&gt;
&lt;li&gt;Filters out only the transactions that are of the type "request", as these are the "request" money transactions that this app generates&lt;/li&gt;
&lt;li&gt;Stores them in the global &lt;code&gt;transactions&lt;/code&gt; array for later usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Define Startup Jobs
&lt;/h3&gt;

&lt;p&gt;The next thing you'll do is define the jobs that need to run each time this Node.js server starts up.&lt;/p&gt;

&lt;p&gt;If you take a look at the startup jobs code block, you'll see what I mean:&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;// Startup jobs&lt;/span&gt;
&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccounts&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&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;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;accounts&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;acct&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;acct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Found primary account: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;. Current balance: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt; &lt;span class="o"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Downloading initial list of transactions.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;updateTransactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="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;What this code does is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the Coinbase API to list all Accounts (these are the places you can store money in Coinbase)&lt;/li&gt;
&lt;li&gt;Look through each Account until it finds the primary (this is usually your Bitcoin wallet used to store Bitcoin)&lt;/li&gt;
&lt;li&gt;Sets the global &lt;code&gt;account&lt;/code&gt; variable to this value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, once the proper Account object has been found, this code will execute the &lt;code&gt;updateTransactions&lt;/code&gt; helper function defined earlier, to build the initial in-memory cache of transactions.&lt;/p&gt;

&lt;p&gt;This way, shortly after the web server starts running all transaction data will be available for querying.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define Server Management Code
&lt;/h3&gt;

&lt;p&gt;Towards the bottom of the &lt;code&gt;server.js&lt;/code&gt; file you'll see a few things:&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;// Cron jobs&lt;/span&gt;
&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;updateTransactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Server management&lt;/span&gt;
&lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&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;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;setInterval()&lt;/code&gt; call essentially tells this Node.js process to update the cache of transaction data once per hour (in milliseconds). This way, all transaction information will be at most one hour old.&lt;/p&gt;

&lt;p&gt;Finally, the Express app itself will be launched once the authentication library has finished preparing itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: It's important not to run the web server (&lt;code&gt;app.listen(PORT);&lt;/code&gt;) until the OIDC library emits the "ready" event. This could result in odd security edge cases where a user making requests to protected pages on your website runs into errors if they make a request before the OIDC library has finished configuring itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Routes
&lt;/h3&gt;

&lt;p&gt;Now that we've gone through the rest of the &lt;code&gt;server.js&lt;/code&gt; code, let's look at the final section we skipped from earlier (the routes):&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;// App routes&lt;/span&gt;
&lt;span class="nx"&gt;app&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="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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;index&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="nx"&gt;app&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="s2"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensureAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dashboard&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;transactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transactions&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensureAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestMoney&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&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="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&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="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&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="nx"&gt;description&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;txn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&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;err&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dashboard&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;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;updateTransactions&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&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;err&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dashboard&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;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dashboard&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;transactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transactions&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="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&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="s2"&gt;/logout&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirect&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first route just displays the home page of the site. Since all we need here is to show a simple template, there's nothing special we need to do other than render the page.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;app.get("/dashboard")&lt;/code&gt; route is what displays the dashboard page when requested. What's important to note here is the additional middleware it uses: &lt;code&gt;oidc.ensureAuthenticated()&lt;/code&gt;. This middleware &lt;em&gt;forces&lt;/em&gt; the user to log in before being able to access this page.&lt;/p&gt;

&lt;p&gt;If you try to visit the &lt;code&gt;/dashboard&lt;/code&gt; page before logging in, for instance, you'll be redirected to the login page and forced to authenticate.&lt;/p&gt;

&lt;p&gt;Once the user has authenticated, however, they'll be allowed into the dashboard page, which simply renders itself using the in-memory cache of transaction data.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;app.post("/dashboard")&lt;/code&gt; route is what handles the invoicing.&lt;/p&gt;

&lt;p&gt;When a user fills out the invoice form and clicks "submit", this route is processed and receives the invoicing data. It then talks to Coinbase using the Coinbase API and generates a proper money request (and email). Finally, before refreshing the page and showing the new list of transactions, this code will force a refresh of the transaction data cache.&lt;/p&gt;

&lt;p&gt;By forcing the cache refresh after each new invoice is created, this prevents an issue where after creating an invoice you would not see it appear in the list below.&lt;/p&gt;

&lt;p&gt;When invoices are generated and Coinbase sends out an email, the client receives an email that looks something like this:&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx2x8ye89sw9fndqsrxgz.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx2x8ye89sw9fndqsrxgz.png" alt="Crypto Invoicer Email"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is quite nice because then a click can simply click the "Complete this payment." button, and be redirected to Coinbase where they can complete the transaction using either Bitcoin or their local currency (USD) to pay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Piece It Together
&lt;/h2&gt;

&lt;p&gt;As I've hopefully shown you, building Bitcoin invoicing software using Node.js can be fairly straightforward.&lt;/p&gt;

&lt;p&gt;The Coinbase API provides a lot of rich functionality. Paired with Okta for authentication and several open source Node.js libraries, you can quickly throw together complicated applications in a small amount of time.&lt;/p&gt;

&lt;p&gt;If you're interested in building cryptocurrency apps of your own, I highly recommend you create a &lt;a href="https://www.coinbase.com/join/51660a68c08669f6b8000046" rel="noopener noreferrer"&gt;Coinbase account&lt;/a&gt; and check out their fantastic &lt;a href="https://developers.coinbase.com/" rel="noopener noreferrer"&gt;API documentation&lt;/a&gt;. They have a good number of libraries and tools available to help you build your applications in a fun and fast way.&lt;/p&gt;

&lt;p&gt;I'd also recommend creating an &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;Okta developer account&lt;/a&gt; which you can use to store users for your web apps, mobile apps, and API services, as well as handle authentication, authorization, OAuth 2.0, OpenID Connect, Single Sign-On, etc.&lt;/p&gt;

&lt;p&gt;Finally, if you'd like to see more articles like this, tweet &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;@oktadev&lt;/a&gt; and let me know! &amp;lt;3 You can also look at some similar articles we've written recently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.okta.com/blog/2018/01/18/cryptocurrency-pwa-secured-by-okta" rel="noopener noreferrer"&gt;Protect Your Cryptocurrency Wealth Tracking PWA with
Okta&lt;/a&gt;
written by my colleague &lt;a href="https://twitter.com/mraible" rel="noopener noreferrer"&gt;@mraible&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.okta.com/blog/2017/09/06/build-a-cryptocurrency-comparison-site-with-vuejs" rel="noopener noreferrer"&gt;Build a Cryptocurrency Comparison Site with
Vue.js&lt;/a&gt;
by yours truly&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>bitcoin</category>
      <category>coinbase</category>
      <category>security</category>
      <category>node</category>
    </item>
    <item>
      <title>Webhooks vs Serverless</title>
      <dc:creator>Randall Degges</dc:creator>
      <pubDate>Mon, 22 Jan 2018 18:10:39 +0000</pubDate>
      <link>https://dev.to/oktadev/webhooks-vs-serverless-1end</link>
      <guid>https://dev.to/oktadev/webhooks-vs-serverless-1end</guid>
      <description>&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%2F4tu4oue1aqzfv8i48emi.jpg" 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%2F4tu4oue1aqzfv8i48emi.jpg" alt="Monster Battle" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you’ve built a successful software-as-a-service product, you tend to run into interesting technical (and business) questions. My favorite question is: “How do we add more functionality to our platform faster?” It’s an interesting question because &lt;em&gt;everyone&lt;/em&gt; wants to build features faster.&lt;/p&gt;

&lt;p&gt;In a perfect world, you’d be able to hire 100,000 engineers, split them into teams of four (&lt;em&gt;with no managers!&lt;/em&gt;), and have each team own a feature: spec it out, build it, iterate on it with user feedback, and do it all in perfect harmony with every other team.&lt;/p&gt;

&lt;p&gt;But let’s get real. This isn’t a perfect world, there’s no way a company would ever have four engineers work in a team without management (&lt;em&gt;ha&lt;/em&gt;)!&lt;/p&gt;

&lt;p&gt;So while you may not be able to build features at a fast enough pace to keep up with your product and user growth, you can cheat your way around it with a popular hack: platform extensibility.&lt;/p&gt;

&lt;p&gt;Instead of requiring your engineers to sit down and develop every single feature every single user has ever requested, you can turn your product into a “platform” that your customer’s developers can build against. This way, if a customer wants a feature badly enough, they can integrate with your platform APIs and BAM: the previously unavailable feature can now be made available! It’s ingenious.&lt;/p&gt;

&lt;p&gt;So how do you (as a successful business owner) allow other developers to extend your platform? You’ve got a lot of choices. Most of them are horrible, however, so I’m only going to talk about the most popular two: webhooks and serverless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless is the Answer!
&lt;/h2&gt;

&lt;p&gt;If you’ve been following the internet hype train over the last few years (&lt;em&gt;specifically, since 2014&lt;/em&gt;), you’ll be familiar with the term “serverless”, also known as “lambdas”, “functions-as-a-service”, etc.&lt;/p&gt;

&lt;p&gt;What all these terms basically refer to is a pattern known as &lt;em&gt;serverless extensibility&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In order to accommodate your customers extending your platform, you allow them to upload some code to your servers that you will run when certain events happen in your product.&lt;/p&gt;

&lt;p&gt;I’ll give you a good example.&lt;/p&gt;

&lt;p&gt;Let’s say you’re building an application hosting platform (&lt;em&gt;a-la &lt;a href="https://www.heroku.com/" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;&lt;/em&gt;). Heroku provides functionality like running your application code, logging errors, and provisioning infrastructure (databases, etc.).&lt;/p&gt;

&lt;p&gt;If a customer is using your platform and wants to send an email to their accounting team every time a new database is provisioned, this can be somewhat tricky unless your platform provides either a feature to do this, or extensibility options so the customer can do it on their own.&lt;/p&gt;

&lt;p&gt;So, you decide to allow serverless extensibility. A customer can now upload some code (in JavaScript) to run on your platform every time a new piece of infrastructure is provisioned.&lt;/p&gt;

&lt;p&gt;The customer reads through your docs, and writes a small function that looks something like this:&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;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;provision&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database&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;// some code to send an email to the accounting department&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;And then uploads it to your website.&lt;/p&gt;

&lt;p&gt;This is pretty cool for the customer! Without needing to bug you and wait for your engineering team to build this email feature out, they were able to write some code to accomplish exactly what they wanted!&lt;/p&gt;

&lt;p&gt;And not only can customers “hook” into your platform when infrastructure is being provisioned: they can hook in anywhere! Your platform provides tons of different extensibility options to make it possible for customers to run their code after or before almost every major platform event!&lt;/p&gt;

&lt;p&gt;There are a few core benefits to this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The customer can easily build out features they need, and not be bottlenecked by the speed of your engineering team&lt;/li&gt;
&lt;li&gt;You lose fewer customers because they’ve now got a way to work around issues in your product&lt;/li&gt;
&lt;li&gt;You’re able to iterate more quickly on your core platform product because you’re now able to narrow your scope&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Flip Side of Serverless
&lt;/h2&gt;

&lt;p&gt;So now that you’ve built out serverless extensibility functionality for your customers you’ve opened up an infinite amount of customization options. But at what cost?&lt;/p&gt;

&lt;p&gt;John, who runs Engineering for one of your largest customers, didn’t sign up for this. Your serverless extensibility created a bunch of ongoing work for him and his team:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;He has to figure out how your serverless functions work, what hooks are available, etc. This is a high learning curve and requires all of his engineers to have a thorough understanding of your product in order to be productive.&lt;/li&gt;
&lt;li&gt;Because your serverless platform only supports running JavaScript ES5 code at the moment, John’s team of C# engineers are having issues writing their complex application logic in JavaScript which they are not all familiar with.&lt;/li&gt;
&lt;li&gt;John’s team doesn’t have any insight into how your serverless platform is running his code: they can’t figure out how to monitor server resources, how to do proper unit and integration testing, how to look for failures, etc.&lt;/li&gt;
&lt;li&gt;John’s team now has to manage code in many different places as opposed to just one GitHub repository. Now, each serverless function John’s team writes must be manually uploaded into the right place in your platform website, maintained, and updated from time to time. Because there is no direct way to integrate these serverless functions into the team’s existing codebase, this code is now fragmented across your platform which makes it hard to work with.&lt;/li&gt;
&lt;li&gt;John’s team is now in a sticky security situation: they’ve got to write proprietary code and store it on YOUR platform. They’ve also got to store sensitive credentials like their email account information, and any other related credentials required to run their serverless software. The security team at John’s company isn’t thrilled.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The larger the company, the more challenging this becomes. Coordinating between different groups of engineers to figure out where a particular piece of functionality is located is difficult and time-consuming. Updating previous hooks becomes a test of patience. And documentation for the team’s codebase becomes exponentially larger to include all of the domain-specific knowledge required to write, update, and maintain these serverless hooks.&lt;/p&gt;

&lt;p&gt;These side effects negate the purpose of the original goal: to let customers get functionality they need faster.&lt;/p&gt;

&lt;p&gt;And these are just the &lt;em&gt;customer facing&lt;/em&gt; side effects you’ll notice. There’s a vast array of other messes this will cause you and your company:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You’ve got to build secure, isolated code execution environments to run customer code in a sandbox. This is incredibly hard in practice. If you search for “&lt;a href="http://lmgtfy.com/?q=docker+escalation" rel="noopener noreferrer"&gt;docker escalation&lt;/a&gt;” on Google, you’ll see what I mean. Even amazing services like Amazon Lambda (the first really serverless player) that have incredibly large security teams can expose themselves to funny &lt;a href="https://www.youtube.com/watch?v=YZ058hmLuv0" rel="noopener noreferrer"&gt;security&lt;/a&gt; issues.&lt;/li&gt;
&lt;li&gt;You’ve got to ensure you respect the customer’s software IP that is now running in your infrastructure&lt;/li&gt;
&lt;li&gt;You’ve got to scale your infrastructure to support arbitrary amounts of customer code in addition to worrying about your own service issues&lt;/li&gt;
&lt;li&gt;You’ve got to expose more and more transparent tools to allow your customers more insight into your system: error logs, performance monitoring, etc. The list can ultimately go on forever.&lt;/li&gt;
&lt;li&gt;You’ve got to write documentation to explain each and every hook you support and how it works. You’ve also got to show users how to upload the code to your platform, how to test it, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bottom line? Building serverless extensibility functionality into your product will likely be the most expensive thing you ever do, engineering-wise–both for you and your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhooks, Going Beyond Serverless Extensibility
&lt;/h2&gt;

&lt;p&gt;An older approach that’s been tested time and time again, is webhooks. While webhooks are not “old” by any means, they predate serverless extensibility patterns by at least seven years. My buddy &lt;a href="http://progrium.com/blog/" rel="noopener noreferrer"&gt;Jeff Lindsay&lt;/a&gt; coined the term back in 2007.&lt;/p&gt;

&lt;p&gt;The idea behind webhooks is simple: instead of &lt;em&gt;you&lt;/em&gt; running a customer’s code on &lt;em&gt;your platform&lt;/em&gt;, you instead just fire off an HTTP POST request to the customer every time something happens, and the customer can then perform whatever logic they need based on those incoming requests.&lt;/p&gt;

&lt;p&gt;Simple, right?&lt;/p&gt;

&lt;p&gt;This is a great approach because it’s easier to manage and scale for all parties involved.&lt;/p&gt;

&lt;p&gt;It’s simpler for &lt;em&gt;your&lt;/em&gt; company because you now only need to fire off HTTP requests when events happen. You don’t need to worry about executing someone else’s software, scaling it, etc. The most complicated thing you have to do is retry failed HTTP requests (which is mandatory for pretty much all HTTP requests anyhow!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhooks in the Wild
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Twilio
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.twilio.com/" rel="noopener noreferrer"&gt;Twilio&lt;/a&gt; is one of the best known API services in the world. Twilio provides API services to manage telephony stuff: phone calls, SMS messages, MMS messages, etc.&lt;/p&gt;

&lt;p&gt;Since day one, Twilio has provided core webhook support in their platform.&lt;/p&gt;

&lt;p&gt;Let’s say you’re building an SMS application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You buy a phone number through Twilio&lt;/li&gt;
&lt;li&gt;Every time that phone number receives an SMS message, Twilio sends an HTTP POST request to your web server with the message data inside&lt;/li&gt;
&lt;li&gt;You then receive an HTTP POST request to your web app, where you parse the request, figure out what the message said, and then take some action (&lt;em&gt;maybe you send a response, for instance&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using this simple back-and-forth messaging pattern, webhooks allow Twilio customers to easily integrate with the platform and build high-value apps without the hassle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: My good friend &lt;a href="http://carter.rabasa.com/" rel="noopener noreferrer"&gt;Carter Rabasa&lt;/a&gt; at Twilio recently released support for serverless extensibility &lt;em&gt;in addition to&lt;/em&gt; their core webhook support. This was a smart move, as they now appeal to everyone (&lt;em&gt;even people who crazily prefer serverless extensibility patterns!&lt;/em&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Heroku
&lt;/h3&gt;

&lt;p&gt;Remember Heroku from the serverless example before? I hope so!&lt;/p&gt;

&lt;p&gt;Heroku’s application hosting platform recently started &lt;a href="https://blog.heroku.com/heroku-webhooks" rel="noopener noreferrer"&gt;supporting webhooks&lt;/a&gt;, and it’s everything I ever dreamed of, and then some!&lt;/p&gt;

&lt;p&gt;Heroku customers are now able to easily hook into their app infrastructure on Heroku, and perform complex logic to scale their services more easily, cut down cost, keep their ops team informed of issues, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Github
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://developer.github.com/webhooks/" rel="noopener noreferrer"&gt;GitHub webhooks&lt;/a&gt; have been around forever, and are the foundation of many popular developer services like &lt;a href="https://travis-ci.org/" rel="noopener noreferrer"&gt;Travis CI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GitHub webhooks allow you to hook into just about every possible action that can be taken on a source repository. They’re excellent for analyzing code, tracking team performance, automating testing and deploys, as well as a number of other great use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Webhooks In Your Product
&lt;/h2&gt;

&lt;p&gt;Implementing serverless extensibility is hard–both for you and your customers. While there are some people who prefer it, it can be a lot of work for everyone involved.&lt;/p&gt;

&lt;p&gt;As someone who’s been building developer tools and API services for nearly 17 years now, one of which generates nearly 30 billion API requests per month, I’d encourage you to take some time to think about the best possible way for you to open your platform up for customization.&lt;/p&gt;

&lt;p&gt;Picking the wrong extensibility options can be a painful mistake, so it’s a good idea to think through the tradeoffs of both approaches, and pick what makes the most sense for you.&lt;/p&gt;

&lt;p&gt;If you need some help deciding, please &lt;a href="//mailto:randall.degges@okta.com"&gt;drop me a line&lt;/a&gt; or &lt;a href="https://twitter.com/rdegges" rel="noopener noreferrer"&gt;tweet at me&lt;/a&gt;, I’d be happy to help you out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;While both serverless extensibility and webhooks serve the same purpose, one is dramatically simpler than the other.&lt;/p&gt;

&lt;p&gt;Webhooks are a simple solution to a complex problem, while serverless extensibility is a complex solution to a complex problem.&lt;/p&gt;

&lt;p&gt;In computer science, as well as many other areas of professional and personal life, I like to take the simple path.&lt;/p&gt;

&lt;p&gt;I hope this has been useful.&lt;/p&gt;

&lt;p&gt;-Randall&lt;/p&gt;

</description>
      <category>programming</category>
      <category>serverless</category>
      <category>webhooks</category>
    </item>
  </channel>
</rss>
