{"id":22061,"date":"2018-07-02T09:09:35","date_gmt":"2018-07-02T06:09:35","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=22061"},"modified":"2018-07-13T12:27:34","modified_gmt":"2018-07-13T09:27:34","slug":"crud-app-express-js-user-authentication","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/","title":{"rendered":"Build a CRUD App with Express.js and User Authentication"},"content":{"rendered":"<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Web Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_source=Web%20Code%20Geeks&#038;utm_medium=Content%20Syndication&#038;utm_campaign=build%20basic%20node%20app\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a> <\/span><\/p>\n<p>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\u2019s no sign of a slowdown. I\u2019ve been working with Node.js since 2012 and have been excited to see the community and tooling grow and evolve \u2014 there\u2019s no better time to get started with Node.js development than right now.<\/p>\n<p>This tutorial will take you step-by-step through building a fully functional Node.js website. Along the way you\u2019ll learn about Express.js, the most popular web framework, user authentication with <a href=\"https:\/\/developer.okta.com\/blog\/2017\/07\/25\/oidc-primer-part-1?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">OpenID Connect<\/a>, 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\u2019t require any prior experience:<\/p>\n<ul>\n<li><a href=\"https:\/\/nodejs.org\/en\/\">Node.js<\/a><\/li>\n<li><a href=\"https:\/\/expressjs.com\/\">Express.js<\/a> and <a href=\"https:\/\/pugjs.org\/api\/getting-started.html\">Pug<\/a><\/li>\n<li>Okta\u2019s <a href=\"https:\/\/github.com\/okta\/okta-oidc-js\/tree\/master\/packages\/oidc-middleware\">OIDC-middleware<\/a> and <a href=\"https:\/\/github.com\/okta\/okta-sdk-nodejs\">Node SDK<\/a><\/li>\n<li><a href=\"http:\/\/docs.sequelizejs.com\/\">Sequelize.js<\/a>, a popular ORM for working with databases in Node.js<\/li>\n<\/ul>\n<p>If you\u2019d like to skip the tutorial and just check out the fully built project, you can go <a href=\"https:\/\/github.com\/rdegges\/okta-express-blog\">view it on GitHub<\/a>.<\/p>\n<h2>About Express.js<\/h2>\n<p>Express.js is the most popular web framework in the Node.js ecosystem. It\u2019s incredibly simple and minimalistic. Furthermore, there are thousands of developer libraries that work with Express, making developing with it fun and flexible.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/express-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22068\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/express-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3.png\" alt=\"express.js website\" width=\"860\" height=\"558\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/express-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3.png 1254w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/express-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3-300x195.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/express-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3-768x499.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/express-website-screenshot-6e39ae77cc4841f1356326199315a4c10903be4bd18a3dfecd823c27b17d59d3-1024x665.png 1024w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>Regardless of whether you\u2019re trying to build a website or an API, Express.js provides tons of features and a nice developer experience.<\/p>\n<p>Through this tutorial, you\u2019ll 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.<\/p>\n<p>The blog will be built using Express.js, the user interface will be built using Pug, the authentication component will be handled by <a href=\"https:\/\/developer.okta.com\/?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">Okta<\/a>, and the blog post storage and database management will be handled by Sequelize.js.<\/p>\n<h2>Create Your Express.js App<\/h2>\n<p>Before we begin, make sure you have a recent version of Node.js installed. If you don\u2019t already have Node.js installed, please <a href=\"https:\/\/nodejs.org\/en\/download\/package-manager\/\">visit this page<\/a> and install it for your operating system before continuing.<\/p>\n<p>To get your project started quickly you can leverage <a href=\"https:\/\/github.com\/expressjs\/generator\">express-generator<\/a>. This is an officially maintained program that allows you to easily scaffold an Express.js website with minimal effort.<\/p>\n<p>To install <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">express-generator<\/code> run:<\/p>\n<pre class=\"gutter: false;brush:bash\">npm install -g express-generator<\/pre>\n<p>Next, you need to initialize your project. To do this, use the newly installed express-generator program to bootstrap your application:<\/p>\n<pre class=\"gutter: false;brush:bash\">express --view pug blog\r\ncd blog\r\nnpm install\r\nnpm start<\/pre>\n<p>The above command will initialize a new project called <strong>blog<\/strong>, move you into the new project folder, install all project dependencies, and start up a web server.<\/p>\n<p>Once you\u2019ve finished running the commands above, point your favorite browser to <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000<\/code> and you should see your application running:<\/p>\n<h2>Initialize Authentication<\/h2>\n<p>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\u2019ll need to create an OpenID Connect application in Okta. <a href=\"https:\/\/developer.okta.com\/signup\/?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">Sign up for a forever-free developer account<\/a> (or log in if you already have one).<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22075\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443.png\" alt=\"express.js okta signup\" width=\"860\" height=\"542\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443.png 1229w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443-300x189.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443-768x484.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-signup-94ec70377e8a1d69fa41cfcd66d9d7f5faf2044e6a361452d155a02762532443-1024x645.png 1024w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>Once you\u2019ve logged in and land on the dashboard page, copy down the <strong>Org URL<\/strong> pictured below. You will need this later.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22074\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d.png\" alt=\"express.js org url\" width=\"860\" height=\"517\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d.png 1237w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d-300x180.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d-768x461.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-org-url-93fb639009e0f0389af1db64678e6561cd01811348bef6350e487a0aa1aada1d-1024x615.png 1024w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>Then create a new application by browsing to the <strong>Applications<\/strong> tab and clicking <strong>Add Application<\/strong>.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22069\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b.png\" alt=\"express.js app dashboard\" width=\"860\" height=\"459\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b.png 1248w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b-300x160.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b-768x410.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b-1024x546.png 1024w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-dashboard-054d9b9b13c1760fe0fb857a4b39ddefad7b219ce3ea72af617bddc360d0d88b-620x330.png 620w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>Next, click the <strong>Web<\/strong> platform option (since our blog project is a web app).<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22071\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46.png\" alt=\"express.js create app platform\" width=\"860\" height=\"444\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46.png 1250w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46-300x155.png 300w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46-768x396.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-platform-d3aa9a1834906c601d29fd2c7843329dd09c1b5be59f8f35b85e82ffc4cfcc46-1024x528.png 1024w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>On the settings page, enter the following values:<\/p>\n<ul>\n<li><strong>Name<\/strong>: Blog<\/li>\n<li><strong>Base URIs<\/strong>: <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000<\/code><\/li>\n<li><strong>Login redirect URIs<\/strong>: <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000\/users\/callback<\/code><\/li>\n<\/ul>\n<p>You can leave all the other values unchanged.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22072\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816.png\" alt=\"express.js create app settings\" width=\"860\" height=\"929\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816.png 1042w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816-278x300.png 278w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816-768x830.png 768w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-app-settings-4d0c56e9c1ea35eae1922ab70f8948ea6bcf3e2ad2af210a1e524ecde8738816-948x1024.png 948w\" sizes=\"(max-width: 860px) 100vw, 860px\" \/><\/a><\/p>\n<p>Now that your application has been created, copy down the <strong>Client ID<\/strong> and <strong>Client secret<\/strong> values on the following page, you\u2019ll need them soon.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-secrets-d4c5570e7679ca4e5af1c90f8fccc1bed0d880bed69eb4b9a9287aaf1e2398cf.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22070 size-full\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-secrets-d4c5570e7679ca4e5af1c90f8fccc1bed0d880bed69eb4b9a9287aaf1e2398cf.png\" alt=\"express.js app secrets\" width=\"731\" height=\"329\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-secrets-d4c5570e7679ca4e5af1c90f8fccc1bed0d880bed69eb4b9a9287aaf1e2398cf.png 731w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-app-secrets-d4c5570e7679ca4e5af1c90f8fccc1bed0d880bed69eb4b9a9287aaf1e2398cf-300x135.png 300w\" sizes=\"(max-width: 731px) 100vw, 731px\" \/><\/a><\/p>\n<p>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 <strong>API<\/strong> tab at the top of the page followed by the <strong>Create Token<\/strong> button. Give your token a name, preferably the same name as your application, then click <strong>Create Token<\/strong>. Copy down this token value as you will need it soon.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-token-87e20254a5485f3482d1fc6a928df9590fac7b0c7a60fbffaca216078f91626f.png\"><img decoding=\"async\" class=\"aligncenter wp-image-22073 size-full\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-token-87e20254a5485f3482d1fc6a928df9590fac7b0c7a60fbffaca216078f91626f.png\" alt=\"express.js create token\" width=\"596\" height=\"284\" srcset=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-token-87e20254a5485f3482d1fc6a928df9590fac7b0c7a60fbffaca216078f91626f.png 596w, https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/okta-create-token-87e20254a5485f3482d1fc6a928df9590fac7b0c7a60fbffaca216078f91626f-300x143.png 300w\" sizes=\"(max-width: 596px) 100vw, 596px\" \/><\/a><\/p>\n<h2>Install Dependencies<\/h2>\n<p>The first thing you need to do in order to initialize your Express.js app is install all of the required dependencies.<\/p>\n<pre class=\"gutter: false;brush:bash\">npm install express@4.16.3\r\nnpm install @okta\/oidc-middleware@0.1.2\r\nnpm install @okta\/okta-sdk-nodejs@1.1.0\r\nnpm install sqlite3@4.0.1\r\nnpm install sequelize@4.38.0\r\nnpm install async@2.6.1\r\nnpm install slugify@1.3.0\r\nnpm install express-session@1.15.6<\/pre>\n<h2>Define Database Models with Sequelize<\/h2>\n<p>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\u2019m handling.<\/p>\n<p>Create a new file named <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/models.js<\/code> and copy the following code inside of it.<\/p>\n<pre class=\"gutter: false;brush:java\">const Sequelize = require(\"sequelize\");\r\n\r\nconst db = new Sequelize({\r\n  dialect: \"sqlite\",\r\n  storage: \".\/database.sqlite\"\r\n});\r\n\r\nconst Post = db.define(\"post\", {\r\n  title: { type: Sequelize.STRING },\r\n  body: { type: Sequelize.TEXT },\r\n  authorId: { type: Sequelize.STRING },\r\n  slug: { type: Sequelize.STRING }\r\n});\r\n\r\ndb.sync();\r\n\r\nmodule.exports = { Post };<\/pre>\n<p>This code initializes a new SQLite database that will be used to store the blog data and also defines a model called <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Post<\/code> which stores blog posts in the database. Each post has a title, a body, an author ID, and a slug field.<\/p>\n<ul>\n<li>The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">title<\/code> field will hold the title of a post, eg: \u201cA Great Article\u201d<\/li>\n<li>The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">body<\/code> field will hold the body of the article as HTML, eg: \u201c&lt;p&gt;My first post!&lt;\/p&gt;\u201d<\/li>\n<li>The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">authorId<\/code> field will store the author\u2019s 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\u2019s most up-to-date information later.<\/li>\n<li>The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">slug<\/code> field will store the URL-friendly version of the post\u2019s title, eg: \u201ca-great-article\u201d<\/li>\n<\/ul>\n<p><strong>NOTE<\/strong>: If you\u2019ve never used SQLite before, it\u2019s amazing. It\u2019s a database that stores your data in a single file. It\u2019s great for building applications that don\u2019t require a large amount of concurrency, like this simple blog.<\/p>\n<p>The call to <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">db.sync();<\/code> at the bottom of the file will automatically create the database and all of the necessary tables once this JavaScript code runs.<\/p>\n<h2>Initialize Your Express.js App<\/h2>\n<p>The next thing I like to do after defining my database models is to initialize my application code. This typically involves:<\/p>\n<ul>\n<li>Configuring application settings<\/li>\n<li>Installing middlewares that provide functionality to the application<\/li>\n<li>Handling errors<\/li>\n<li>Etc.<\/li>\n<\/ul>\n<p>Open the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/app.js<\/code> file and replace its contents with the following code.<\/p>\n<pre class=\"gutter: false;brush:java\">const createError = require(\"http-errors\");\r\nconst express = require(\"express\");\r\nconst logger = require(\"morgan\");\r\nconst path = require(\"path\");\r\nconst okta = require(\"@okta\/okta-sdk-nodejs\");\r\nconst session = require(\"express-session\");\r\nconst ExpressOIDC = require(\"@okta\/oidc-middleware\").ExpressOIDC;\r\n\r\nconst blogRouter = require(\".\/routes\/blog\");\r\nconst usersRouter = require(\".\/routes\/users\");\r\n\r\n\r\nconst app = express();\r\nconst client = new okta.Client({\r\n  orgUrl: \"{yourOktaOrgUrl}\",\r\n  token: \"{yourOktaToken}\"\r\n});\r\n\r\napp.set(\"views\", path.join(__dirname, \"views\"));\r\napp.set(\"view engine\", \"pug\");\r\n\r\n\/\/ Middleware\r\napp.use(logger(\"dev\"));\r\napp.use(express.json());\r\napp.use(express.urlencoded({ extended: false }));\r\napp.use(express.static(path.join(__dirname, \"public\")));\r\n\r\nconst oidc = new ExpressOIDC({\r\n  issuer: \"{yourOktaOrgUrl}\/oauth2\/default\",\r\n  client_id: \"{yourOktaClientId}\",\r\n  client_secret: \"{yourOktaClientSecret}\",\r\n  redirect_uri: \"http:\/\/localhost:3000\/users\/callback\",\r\n  scope: \"openid profile\",\r\n  routes: {\r\n    login: {\r\n      path: \"\/users\/login\"\r\n    },\r\n    callback: {\r\n      path: \"\/users\/callback\",\r\n      defaultRedirect: \"\/dashboard\"\r\n    }\r\n  }\r\n});\r\n\r\napp.use(session({\r\n  secret: \"{aLongRandomString}\",\r\n  resave: true,\r\n  saveUninitialized: false\r\n}));\r\n\r\napp.use(oidc.router);\r\n\r\napp.use((req, res, next) =&gt; {\r\n  if (!req.userinfo) {\r\n    return next();\r\n  }\r\n\r\n  client.getUser(req.userinfo.sub)\r\n    .then(user =&gt; {\r\n      req.user = user;\r\n      res.locals.user = user;\r\n      next();\r\n    });\r\n});\r\n\r\n\/\/ Routes\r\napp.use(\"\/\", blogRouter);\r\napp.use(\"\/users\", usersRouter);\r\n\r\n\/\/ Error handlers\r\napp.use(function(req, res, next) {\r\n  next(createError(404));\r\n});\r\n\r\napp.use(function(err, req, res, next) {\r\n  res.locals.message = err.message;\r\n  res.locals.error = req.app.get(\"env\") === \"development\" ? err : {};\r\n\r\n  res.status(err.status || 500);\r\n  res.render(\"error\");\r\n});\r\n\r\n\r\nmodule.exports = app;<\/pre>\n<p>Be sure to replace the placeholder variables with your actual Okta information.<\/p>\n<ul>\n<li>Replace <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaOrgUrl}<\/code> with the Org URL on your dashboard page<\/li>\n<li>Replace <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaClientId}<\/code> with the Client ID on your application page<\/li>\n<li>Replace <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaClientSecret}<\/code> with the Client secret on your application page<\/li>\n<li>Replace <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{aLongRandomString}<\/code> with a long random string (just mash your fingers on the keyboard for a second)<\/li>\n<\/ul>\n<p>Let\u2019s take a look at what this code does.<\/p>\n<h3>Initialize Node.js Middlewares<\/h3>\n<p>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.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Middleware\r\napp.use(logger(\"dev\"));\r\napp.use(express.json());\r\napp.use(express.urlencoded({ extended: false }));\r\napp.use(express.static(path.join(__dirname, \"public\")));\r\n\r\nconst oidc = new ExpressOIDC({\r\n  issuer: \"{yourOktaOrgUrl}\/oauth2\/default\",\r\n  client_id: \"yourOktaClientId}\",\r\n  client_secret: \"{yourOktaClientSecret}\",\r\n  redirect_uri: \"http:\/\/localhost:3000\/users\/callback\",\r\n  scope: \"openid profile\",\r\n  routes: {\r\n    login: {\r\n      path: \"\/users\/login\"\r\n    },\r\n    callback: {\r\n      path: \"\/users\/callback\",\r\n      defaultRedirect: \"\/dashboard\"\r\n    }\r\n  }\r\n});\r\n\r\napp.use(session({\r\n  secret: \"{aLongRandomString}\",\r\n  resave: true,\r\n  saveUninitialized: false\r\n}));\r\n\r\napp.use(oidc.router);\r\n\r\napp.use((req, res, next) =&gt; {\r\n  if (!req.userinfo) {\r\n    return next();\r\n  }\r\n\r\n  client.getUser(req.userinfo.sub)\r\n    .then(user =&gt; {\r\n      req.user = user;\r\n      res.locals.user = user;\r\n\r\n      next();\r\n    });\r\n});<\/pre>\n<p>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 <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ExpressOIDC<\/code> middleware.<\/p>\n<p>This middleware handles the OpenID Connect authentication logic of the application which supports login, logout, etc. The settings being passed into the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ExpressOIDC<\/code> 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\u2019ve been logged in.<\/p>\n<p>The next middleware is the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">session<\/code> middleware. This middleware is responsible for managing user cookies and remembering who a user is. The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">secret<\/code> it takes must be a long random string you define and keep private. This secret makes it impossible for attackers to tamper with cookies.<\/p>\n<p>The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">oidc.router<\/code> middleware uses the settings you defined when creating <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ExpressOIDC<\/code> to create routes for handling user authentication. Whenever a user visits <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/users\/login<\/code>, for instance, they\u2019ll be taken to a login page. This line of code is what makes that possible.<\/p>\n<p>Finally, there\u2019s a custom middleware. This middleware creates a <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">req.user<\/code> object that you will be able to use later on to more easily access a currently logged in user\u2019s personal information.<\/p>\n<h3>Initialize Node.js Routes<\/h3>\n<p>The route code tells Express.js what code to run when a user visits a particular URL. Here is the route code from the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/app.js<\/code>.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Routes\r\napp.use(\"\/\", blogRouter);\r\napp.use(\"\/users\", usersRouter);<\/pre>\n<p>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 <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/users<\/code>, Express.js will look for other matching URLs in the user routes file. If a user visits any URLs starting with the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/<\/code> URL, Express.js will look in the blog routes file to see what to do.<\/p>\n<h3>Initialize Error Handlers<\/h3>\n<p>The last bit of code in our app above is the error-handling middlewares.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Error handlers\r\napp.use(function(req, res, next) {\r\n  next(createError(404));\r\n});\r\n\r\napp.use(function(err, req, res, next) {\r\n  res.locals.message = err.message;\r\n  res.locals.error = req.app.get(\"env\") === \"development\" ? err : {};\r\n\r\n  res.status(err.status || 500);\r\n  res.render(\"error\");\r\n});<\/pre>\n<p>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.<\/p>\n<h2>Create Express.js Views<\/h2>\n<p>Views in Express.js are the equivalent of HTML templates\u2014they\u2019re the place you store front-end code and logic. The views you\u2019ll use in this project will use the <a href=\"https:\/\/pugjs.org\/api\/getting-started.html\">Pug<\/a> templating language which is one of the most popular.<\/p>\n<p>Remove your existing views by running the following command.<\/p>\n<pre class=\"gutter: false;brush:bash\">rm views\/*<\/pre>\n<p>Next, create a <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/layout.pug<\/code> file. This is a base \u201clayout\u201d template that all other templates will inherit from. It defines common HTML, includes the <a href=\"https:\/\/getbootstrap.com\/\">Bootstrap<\/a> CSS library, and also defines a simple navigation menu.<\/p>\n<pre class=\"gutter: false;brush:html\">block variables\r\n  - var selected = 'Home'\r\n\r\ndoctype html\r\nhtml(lang='en')\r\n  head\r\n    meta(charset='utf-8')\r\n    meta(name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no')\r\n    link(rel='stylesheet' href='https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/4.0.0\/css\/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW\/dAiS6JXm' crossorigin='anonymous')\r\n    link(rel='stylesheet', href='\/stylesheets\/style.css')\r\n    title Blog: #{title}\r\n  body\r\n    div.d-flex.flex-column.flex-md-row.align-items-center.p-3.px-md-4.mb-3.bg-white.border-bottom.box-shadow\r\n      h5.my-0.mr-md-auto.font-weight-normal Blog\r\n      nav.my-2.my-md-0.mr-md-3\r\n        a.p-2.text-dark(href=\"\/\", title=\"Home\") Home\r\n\r\n        if user == undefined\r\n          a.p-2.text-dark(href=\"\/users\/login\") Log In\r\n        else\r\n          a.p-2.text-dark(href=\"\/dashboard\") Dashboard\r\n          a.p-2.text-dark(href=\"\/users\/logout\") Logout\r\n    .container\r\n      block content\r\n\r\n    hr.bottom\r\n    footer.\r\n      Built with #[a(href='https:\/\/expressjs.com\/') Express.js], login powered by #[a(href='https:\/\/developer.okta.com\/') Okta].<\/pre>\n<p>Next, create the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/error.pug<\/code> file. This page will be shown when an error occurs.<\/p>\n<pre class=\"gutter: false;brush:html\">extends layout\r\n\r\nblock content\r\n  h1= message\r\n  h2= error.status\r\n  pre #{error.stack}<\/pre>\n<p>Next, create the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/unauthenticated.pug<\/code> file. This page will be shown when a user tries to visit a page but they aren\u2019t logged in.<\/p>\n<pre class=\"gutter: false;brush:html\">extends layout\r\n\r\nblock variables\r\n  - var title = \"Unauthenticated\"\r\n\r\nblock content\r\n  .unauthenticated\r\n    h2.text-center Whoops!\r\n    p.\r\n      You must be signed in to view this page. Please #[a(href=\"\/users\/login\", title=\"Login\") login] to view this page.<\/pre>\n<p>Now define the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/index.pug<\/code> template. This is the homepage of the website and lists all the current blog posts ordered by date.<\/p>\n<pre class=\"gutter: false;brush:html\">extends layout\r\n\r\nblock variables\r\n  - var title = \"Home\"\r\n\r\nblock content\r\n  h2.text-center Recent Posts\r\n\r\n  if posts == null\r\n    p.empty.text-center Uh oh. There are no posts to view!\r\n\r\n  .posts\r\n    ul\r\n      each post in posts\r\n        .row\r\n          .offset-sm-2.col-sm-8\r\n            li\r\n              a(href=\"\/\" + post.slug, title=post.title)= post.title\r\n              span   by #{post.authorName}<\/pre>\n<p>The next view to define is <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/post.pug<\/code> which displays a single blog post.<\/p>\n<pre class=\"gutter: false;brush:html\">extends layout\r\n\r\nblock variables\r\n  - var title = post.title\r\n\r\nblock content\r\n  h2.text-center= title\r\n\r\n  .row\r\n    .offset-sm-2.col-sm-8\r\n      .body !{post.body}\r\n      p.author Written by #{post.authorName}<\/pre>\n<p>Now create the file <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/edit.pug<\/code> which contains the blog post editing page markup.<\/p>\n<pre class=\"gutter: false;brush:html\">extends layout\r\n\r\nblock variables\r\n  - var title = post.title\r\n\r\nblock content\r\n  h2.text-center Edit Post\r\n\r\n  .row\r\n    .offset-sm-2.col-sm-8\r\n      form(method=\"post\")\r\n        .form-group\r\n          label(for=\"title\") Post Title\r\n          input.form-control#title(type=\"text\", name=\"title\", value=post.title, required)\r\n        .form-group\r\n          label(for=\"body\") Post Body\r\n          textarea.form-control#post(name=\"body\", rows=\"6\", required)= post.body\r\n        button.btn.btn-primary.submit-btn(type=\"submit\") Update\r\n\r\n  .row\r\n    .offset-sm-2.col-sm-8\r\n      .body !{post.body}\r\n      p.author Written by #{post.authorName}<\/pre>\n<p>Finally, create <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/views\/dashboard.pug<\/code> which will render the dashboard page that users will see once they\u2019ve logged in. This page allows a user to create a new post as well as edit and delete their existing posts.<\/p>\n<pre class=\"gutter: false;brush:html\">extends layout\r\n\r\nblock variables\r\n  - var title = \"Dashboard\"\r\n\r\nblock content\r\n  .row\r\n    .offset-sm-2.col-sm-8\r\n      h2 Create a Post\r\n\r\n  if post != undefined\r\n    .row\r\n      .offset-sm-2.col-sm-8\r\n        .alert.alert-success(role=\"alert\").text-center\r\n          p Your new post was created successfully! #[a(href=\"\/\" + post.slug) View it?]\r\n\r\n  .row\r\n    .offset-sm-2.col-sm-8\r\n      form(method=\"post\")\r\n        .form-group\r\n          label(for=\"title\") Post Title\r\n          input.form-control#title(type=\"text\", name=\"title\", placeholder=\"Title\", required)\r\n        .form-group\r\n          label(for=\"body\") Post Body\r\n          textarea.form-control#post(name=\"body\", rows=\"6\", required)\r\n        button.btn.btn-primary.submit-btn(type=\"submit\") Submit\r\n\r\n  .row\r\n    .offset-sm-2.col-sm-8\r\n      h2.your-posts Your Posts\r\n      ul.edit\r\n        each post in posts\r\n          li\r\n            a(href=\"\/\" + post.slug, title=post.title)= post.title\r\n            form.hidden(method=\"post\", action=\"\/\" + post.slug + \"\/delete\")\r\n              button.btn.btn-outline-danger.delete Delete\r\n            a(href=\"\/\" + post.slug + \"\/edit\", title=post.title)\r\n              button.btn.btn-outline-secondary Edit<\/pre>\n<h2>Create Styles<\/h2>\n<p>I\u2019m not much of a web designer (that\u2019s why I like using Bootstrap), but every project needs a bit of visual flair. I\u2019ve done my best to create some simple CSS styling.<\/p>\n<p>Since CSS is straightforward and not the focus of this tutorial, you can simply copy the CSS below into the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/public\/stylesheets\/style.css<\/code> file.<\/p>\n<pre class=\"gutter: false;brush:html\">footer {\r\n  text-align: center;\r\n  font-style: italic;\r\n  margin-top: 1em;\r\n}\r\n\r\n.nav {\r\n  float: right;\r\n}\r\n\r\nh2 {\r\n  margin-bottom: 2em;\r\n}\r\n\r\n.posts ul {\r\n  list-style-type: none;\r\n}\r\n\r\n.posts a {\r\n  font-size: 1.3em;\r\n  text-decoration: underline;\r\n  color: #212529;\r\n}\r\n\r\n.posts span {\r\n  font-size: 1.1em;\r\n  float: right;\r\n}\r\n\r\n.empty {\r\n  font-size: 2em;\r\n  margin-bottom: 5em;\r\n}\r\n\r\n.container {\r\n  padding-top: 2em;\r\n}\r\n\r\n.unauthenticated p {\r\n  font-size: 1.3em;\r\n  text-align: center;\r\n}\r\n\r\nhr.bottom {\r\n  margin-top: 4em;\r\n}\r\n\r\n.submit-btn {\r\n  float: right;\r\n}\r\n\r\n.alert p {\r\n  font-size: 1.1em;\r\n}\r\n\r\n.author {\r\n  font-size: 1.2em;\r\n  margin-top: 2em;\r\n}\r\n\r\n.body {\r\n  margin-top: 2em;\r\n  font-size: 1.2em;\r\n}\r\n\r\n.edit {\r\n  padding-left: 0;\r\n}\r\n\r\n.edit a {\r\n  text-decoration: underline;\r\n  color: #212529;\r\n  font-size: 1.5em;\r\n}\r\n\r\n.edit li {\r\n  list-style-type: none;\r\n  line-height: 2.5em;\r\n}\r\n\r\n.edit button {\r\n  float: right;\r\n}\r\n\r\n.delete {\r\n  margin-left: 1em;\r\n}\r\n\r\n.your-posts {\r\n  margin-top: 2em;\r\n}\r\n\r\n.hidden {\r\n  display: inline;\r\n}<\/pre>\n<h2>Create Routes<\/h2>\n<p>Routes are where the real action happens in any Express.js application. They dictate what happens when a user visits a particular URL.<\/p>\n<p>To get started, remove the existing routes that the express-generator application created.<\/p>\n<pre class=\"gutter: false;brush:bash\">rm routes\/*<\/pre>\n<p>Next, create the two route files that you\u2019ll need.<\/p>\n<pre class=\"gutter: false;brush:bash\">touch routes\/{blog.js,users.js}<\/pre>\n<p>The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/routes\/blog.js<\/code> file will contain all of the routes related to blog functionality. The <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/routes\/users.js<\/code> file will contain the routes related to user functionality. While you could always put all your logic in the main <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/app.js<\/code> file, keeping your routes in separate purpose-based files is a good idea.<\/p>\n<h3>Create User Routes<\/h3>\n<p>Since Okta\u2019s <a href=\"https:\/\/github.com\/okta\/okta-oidc-js\/tree\/master\/packages\/oidc-middleware\">oidc-middleware library<\/a> is already handling user authentication for the application, there isn\u2019t a lot of user-facing functionality we need to create.<\/p>\n<p>The only route you need to define that relates to user management is a logout route \u2014 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\u2019t create an actual route.<\/p>\n<p>Open up the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/routes\/users.js<\/code> file and copy in the following code.<\/p>\n<pre class=\"gutter: false;brush:java\">const express = require(\"express\");\r\n\r\n\r\nconst router = express.Router();\r\n\r\n\/\/ Log a user out\r\nrouter.get(\"\/logout\", (req, res, next) =&gt; {\r\n  req.logout();\r\n  res.redirect(\"\/\");\r\n});\r\n\r\n\r\nmodule.exports = router;<\/pre>\n<p>The way to understand this route is simple. When a user visits the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/logout<\/code> URL, a function will run that:<\/p>\n<p>Uses the oidc-middleware library to log the user out of their account Redirects the now logged-out user to the homepage of the site<\/p>\n<h3>Create Blog Routes<\/h3>\n<p>Since the application you\u2019re 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.<\/p>\n<p>Open up the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.\/routes\/blog.js<\/code> file and copy in the following code. Don\u2019t worry if it looks like a lot all at once &#8211; I\u2019ll walk you through each route in detail below.<\/p>\n<pre class=\"gutter: false;brush:java\">const async = require(\"async\");\r\nconst express = require(\"express\");\r\nconst okta = require(\"@okta\/okta-sdk-nodejs\");\r\nconst sequelize = require(\"sequelize\");\r\nconst slugify = require(\"slugify\");\r\n\r\nconst models = require(\"..\/models\");\r\n\r\n\r\nconst client = new okta.Client({\r\n  orgUrl: \"{yourOktaOrgUrl}\",\r\n  token: \"{yourOktaToken}\"\r\n});\r\nconst router = express.Router();\r\n\r\n\/\/ Only let the user access the route if they are authenticated.\r\nfunction ensureAuthenticated(req, res, next) {\r\n  if (!req.user) {\r\n    return res.status(401).render(\"unauthenticated\");\r\n  }\r\n\r\n  next();\r\n}\r\n\r\n\/\/ Render the home page and list all blog posts\r\nrouter.get(\"\/\", (req, res) =&gt; {\r\n  models.Post.findAll({\r\n    order: sequelize.literal(\"createdAt DESC\")\r\n  }).then(posts =&gt; {\r\n    let postData = [];\r\n\r\n    async.eachSeries(posts, (post, callback) =&gt; {\r\n      post = post.get({ plain: true });\r\n      client.getUser(post.authorId).then(user =&gt; {\r\n        postData.push({\r\n          title: post.title,\r\n          body: post.body,\r\n          createdAt: post.createdAt,\r\n          authorName: user.profile.firstName + \" \" + user.profile.lastName,\r\n          slug: post.slug\r\n        });\r\n        callback();\r\n      }).catch(err =&gt; {\r\n        postData.push({\r\n          title: post.title,\r\n          body: post.body,\r\n          createdAt: post.createdAt,\r\n          slug: post.slug\r\n        });\r\n        callback();\r\n      });\r\n    }, err =&gt; {\r\n      return res.render(\"index\", { posts: postData });\r\n    });\r\n  });\r\n});\r\n\r\n\/\/ Render the user dashboard\r\nrouter.get(\"\/dashboard\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.findAll({\r\n    where: {\r\n      authorId: req.user.id\r\n    },\r\n    order: sequelize.literal(\"createdAt DESC\")\r\n  }).then(posts =&gt; {\r\n    let postData = [];\r\n\r\n    posts.forEach(post =&gt; {\r\n      postData.push(post.get({ plain: true }));\r\n    });\r\n\r\n    return res.render(\"dashboard\", { posts: postData });\r\n  });\r\n});\r\n\r\n\/\/ Create a new post\r\nrouter.post(\"\/dashboard\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.create({\r\n    title: req.body.title,\r\n    body: req.body.body,\r\n    authorId: req.user.id,\r\n    slug: slugify(req.body.title).toLowerCase()\r\n  }).then(newPost =&gt; {\r\n    models.Post.findAll({\r\n      where: {\r\n        authorId: req.user.id\r\n      },\r\n      order: sequelize.literal(\"createdAt DESC\")\r\n    }).then(posts =&gt; {\r\n      let postData = [];\r\n\r\n      posts.forEach(post =&gt; {\r\n        postData.push(post.get({ plain: true }));\r\n      });\r\n\r\n      res.render(\"dashboard\", { post: newPost, posts: postData });\r\n    });\r\n  });\r\n});\r\n\r\n\/\/ Render the edit post page\r\nrouter.get(\"\/:slug\/edit\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug,\r\n      authorId: req.user.id\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post = post.get({ plain: true });\r\n    client.getUser(post.authorId).then(user =&gt; {\r\n      post.authorName = user.profile.firstName + \" \" + user.profile.lastName;\r\n      res.render(\"edit\", { post });\r\n    });\r\n  });\r\n});\r\n\r\n\/\/ Update a post\r\nrouter.post(\"\/:slug\/edit\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug,\r\n      authorId: req.user.id\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post.update({\r\n      title: req.body.title,\r\n      body: req.body.body,\r\n      slug: slugify(req.body.title).toLowerCase()\r\n    }).then(() =&gt; {\r\n      post = post.get({ plain: true });\r\n      client.getUser(post.authorId).then(user =&gt; {\r\n        post.authorName = user.profile.firstName + \" \" + user.profile.lastName;\r\n        res.redirect(\"\/\" + slugify(req.body.title).toLowerCase());\r\n      });\r\n    });\r\n  });\r\n});\r\n\r\n\/\/ Delete a post\r\nrouter.post(\"\/:slug\/delete\", (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug,\r\n      authorId: req.user.id\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post.destroy();\r\n    res.redirect(\"\/dashboard\");\r\n  });\r\n});\r\n\r\n\/\/ View a post\r\nrouter.get(\"\/:slug\", (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post = post.get({ plain: true });\r\n    client.getUser(post.authorId).then(user =&gt; {\r\n      post.authorName = user.profile.firstName + \" \" + user.profile.lastName;\r\n      res.render(\"post\", { post });\r\n    });\r\n  });\r\n});\r\n\r\n\r\nmodule.exports = router;<\/pre>\n<p><strong>NOTE<\/strong>: Make sure you substitute in your values for the placeholder variables towards the top of this file. You need to replace <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaOrgUrl}<\/code> and <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{yourOktaToken}<\/code> with the appropriate values.<\/p>\n<p>This is a lot of code, so let\u2019s take a look at each route and how it works.<\/p>\n<h4>Create an Authentication Helper<\/h4>\n<p>The first function you\u2019ll notice in the blog routes is the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ensureAuthenticated<\/code> function.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Only let the user access the route if they are authenticated.\r\nfunction ensureAuthenticated(req, res, next) {\r\n  if (!req.user) {\r\n    return res.status(401).render(\"unauthenticated\");\r\n  }\r\n\r\n  next();\r\n}<\/pre>\n<p>This function is a special middleware you\u2019ll use later on that will render the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">unauthenticated.pug<\/code> view you created earlier to tell the user they don\u2019t have access to view the page unless they log in.<\/p>\n<p>This middleware works by looking for the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">req.user<\/code> variable which, if it doesn\u2019t 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).<\/p>\n<h4>Create the Homepage<\/h4>\n<p>The index route (aka: \u201chomepage route\u201d) 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\u2019s the route code.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Render the home page and list all blog posts\r\nrouter.get(\"\/\", (req, res) =&gt; {\r\n  models.Post.findAll({\r\n    order: sequelize.literal(\"createdAt DESC\")\r\n  }).then(posts =&gt; {\r\n    let postData = [];\r\n\r\n    async.eachSeries(posts, (post, callback) =&gt; {\r\n      post = post.get({ plain: true });\r\n      client.getUser(post.authorId).then(user =&gt; {\r\n        postData.push({\r\n          title: post.title,\r\n          body: post.body,\r\n          createdAt: post.createdAt,\r\n          authorName: user.profile.firstName + \" \" + user.profile.lastName,\r\n          slug: post.slug\r\n        });\r\n        callback();\r\n      }).catch(err =&gt; {\r\n        postData.push({\r\n          title: post.title,\r\n          body: post.body,\r\n          createdAt: post.createdAt,\r\n          slug: post.slug\r\n        });\r\n        callback();\r\n      });\r\n    }, err =&gt; {\r\n      return res.render(\"index\", { posts: postData });\r\n    });\r\n  });\r\n});<\/pre>\n<p>The way this works is by first using <a href=\"http:\/\/docs.sequelizejs.com\/\">Sequelize.js<\/a> to retrieve a list of all blog posts from the database ordered by the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">createdAt<\/code> field. Whenever a new blog post is stored in the database, Sequelize.js automatically assigns it both a <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">createdAt<\/code> and <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">updatedAt<\/code> time field.<\/p>\n<p>Once a list of posts have been returned from the database you will iterate over each post retrieving it in JSON format, then use <a href=\"https:\/\/github.com\/okta\/okta-sdk-nodejs\">Okta\u2019s Node SDK<\/a> to retrieve the author\u2019s information via the authorId field.<\/p>\n<p>Finally, you\u2019ll build an array consisting of all the blog posts alongside the author\u2019s name, and will render the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">index.pug<\/code> template which then takes that data and displays the full web page.<\/p>\n<h4>Create the Dashboard Routes<\/h4>\n<p>The dashboard page is the first page users will see after logging in. It will:<\/p>\n<ul>\n<li>Allow users to create a new blog post<\/li>\n<li>Show users a list of their previously created blog posts<\/li>\n<li>Provide buttons that allow a user to edit or delete previously created blog posts<\/li>\n<\/ul>\n<p>Here\u2019s the code that powers the dashboard route.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Render the user dashboard\r\nrouter.get(\"\/dashboard\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.findAll({\r\n    where: {\r\n      authorId: req.user.id\r\n    },\r\n    order: sequelize.literal(\"createdAt DESC\")\r\n  }).then(posts =&gt; {\r\n    let postData = [];\r\n\r\n    posts.forEach(post =&gt; {\r\n      postData.push(post.get({ plain: true }));\r\n    });\r\n\r\n    return res.render(\"dashboard\", { posts: postData });\r\n  });\r\n});\r\n\r\n\/\/ Create a new post\r\nrouter.post(\"\/dashboard\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.create({\r\n    title: req.body.title,\r\n    body: req.body.body,\r\n    authorId: req.user.id,\r\n    slug: slugify(req.body.title).toLowerCase()\r\n  }).then(newPost =&gt; {\r\n    models.Post.findAll({\r\n      where: {\r\n        authorId: req.user.id\r\n      },\r\n      order: sequelize.literal(\"createdAt DESC\")\r\n    }).then(posts =&gt; {\r\n      let postData = [];\r\n\r\n      posts.forEach(post =&gt; {\r\n        postData.push(post.get({ plain: true }));\r\n      });\r\n\r\n      res.render(\"dashboard\", { post: newPost, posts: postData });\r\n    });\r\n  });\r\n});<\/pre>\n<p>Note that there are technically two routes here. The first route function is run when a user issues a GET request for the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/dashboard<\/code> page, while the second route is run when a user issues a <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">POST<\/code> request for the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/dashboard<\/code> page.<\/p>\n<p>The first route retrieves a list of all blog posts this user has created, then renders the dashboard page. Note how it uses the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ensureAuthenticated<\/code> middleware we created earlier. By inserting the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ensureAuthenticated<\/code> middleware into the route, this guarantees that this route code will only execute if a currently logged in user is visiting this page.<\/p>\n<p>If a user chooses to create a new blog post, that will trigger a POST request to the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/dashboard<\/code> URL, which is what will eventually run the second dashboard route shown above.<\/p>\n<p>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.<\/p>\n<h4>Create the Edit Routes<\/h4>\n<p>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.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Render the edit post page\r\nrouter.get(\"\/:slug\/edit\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug,\r\n      authorId: req.user.id\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post = post.get({ plain: true });\r\n    client.getUser(post.authorId).then(user =&gt; {\r\n      post.authorName = user.profile.firstName + \" \" + user.profile.lastName;\r\n      res.render(\"edit\", { post });\r\n    });\r\n  });\r\n});\r\n\r\n\/\/ Update a post\r\nrouter.post(\"\/:slug\/edit\", ensureAuthenticated, (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug,\r\n      authorId: req.user.id\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post.update({\r\n      title: req.body.title,\r\n      body: req.body.body,\r\n      slug: slugify(req.body.title).toLowerCase()\r\n    }).then(() =&gt; {\r\n      post = post.get({ plain: true });\r\n      client.getUser(post.authorId).then(user =&gt; {\r\n        post.authorName = user.profile.firstName + \" \" + user.profile.lastName;\r\n        res.redirect(\"\/\" + slugify(req.body.title).toLowerCase());\r\n      });\r\n    });\r\n  });\r\n});<\/pre>\n<p>These routes by matching a variable pattern URL. If the user visits a URL that looks like <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/&lt;something&gt;\/edit<\/code>, then the edit route will run. Because the URL pattern in the route is defined as <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/:slug\/edit<\/code>, Express.js will pass along the URL route in the <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">req.params.slug<\/code> variable so you can use it.<\/p>\n<p>These routes handle rendering the edit page as well as updating existing posts when needed.<\/p>\n<h4>Create the Delete Route<\/h4>\n<p>The delete route is simple: if a user sends a POST request to the URL <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/&lt;post-url&gt;\/delete<\/code>, then Sequelize.js will destroy the post from the database.<\/p>\n<p>Here\u2019s the code that makes this work.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ Delete a post\r\nrouter.post(\"\/:slug\/delete\", (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug,\r\n      authorId: req.user.id\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post.destroy();\r\n    res.redirect(\"\/dashboard\");\r\n  });\r\n});<\/pre>\n<h4>Create the Display Route<\/h4>\n<p>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.<\/p>\n<p>When a user visits a URL like <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/my-great-article<\/code>, this route will run, query the database for any blog posts whose slug is <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">my-great-article<\/code>, then display that post on a page.<\/p>\n<pre class=\"gutter: false;brush:java\">\/\/ View a post\r\nrouter.get(\"\/:slug\", (req, res, next) =&gt; {\r\n  models.Post.findOne({\r\n    where: {\r\n      slug: req.params.slug\r\n    }\r\n  }).then(post =&gt; {\r\n    if (!post) {\r\n      return res.render(\"error\", {\r\n        message: \"Page not found.\",\r\n        error: {\r\n          status: 404,\r\n        }\r\n      });\r\n    }\r\n\r\n    post = post.get({ plain: true });\r\n    client.getUser(post.authorId).then(user =&gt; {\r\n      post.authorName = user.profile.firstName + \" \" + user.profile.lastName;\r\n      res.render(\"post\", { post });\r\n    });\r\n  });\r\n});<\/pre>\n<h2>Test Your New CRUD App!<\/h2>\n<p>By this point, you\u2019ve 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 <code class=\"highlighter-rouge\" style=\"font-size: 13px;\">http:\/\/localhost:3000<\/code> in the browser.<\/p>\n<pre class=\"gutter: false;brush:bash\">npm start<\/pre>\n<p>If you were able to copy the code properly, you should be able to log in, create posts, edit posts, and delete posts.<\/p>\n<p><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/using-the-blog-e3ae169587f9fb88257e95c6e2083b7dc41b8584216e2d576e0af6d4ed0fe823.gif\"><img decoding=\"async\" class=\"aligncenter wp-image-22076\" src=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2018\/06\/using-the-blog-e3ae169587f9fb88257e95c6e2083b7dc41b8584216e2d576e0af6d4ed0fe823.gif\" alt=\"express.js using the blog\" width=\"860\" height=\"579\" \/><\/a><\/p>\n<h2>Do More With Node!<\/h2>\n<p>I hope you enjoyed building a simple CRUD app with Node.js and Express.js. I\u2019ve 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 <a href=\"https:\/\/github.com\/rdegges\/okta-express-blog\">on GitHub<\/a>.<\/p>\n<p>If you\u2019d like to learn more about building web apps in Node, you might want to check out these other great posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/05\/18\/node-authentication-with-passport-and-oidc?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">Build Secure Node Authentication with Passport.js and OpenID Connect<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/02\/06\/build-user-registration-with-node-react-and-okta?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">Build User Registration with Node, React, and Okta<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/04\/24\/simple-node-authentication?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">Simple Node Authentication<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">Build a Basic CRUD App with Vue.js and Node<\/a><\/li>\n<\/ul>\n<p>If you\u2019re interested in learning more about how the underlying authentication components work (OpenID Connect), you may be interested in our <a href=\"https:\/\/developer.okta.com\/blog\/2017\/07\/25\/oidc-primer-part-1?utm_source=Web%20Code%20Geeks&amp;utm_medium=Content%20Syndication&amp;utm_campaign=build%20basic%20node%20app\">OpenID Connect primer series<\/a> which explains everything you need to know about OpenID Connect as a developer.<\/p>\n<p>Finally, please <a href=\"https:\/\/twitter.com\/OktaDev\">follow us on Twitter<\/a> 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!<\/p>\n<p>And\u2026 If you have any questions, please leave a comment below!<\/p>\n<p><a href=\"https:\/\/developer.okta.com\/blog\/2018\/06\/28\/tutorial-build-a-basic-crud-app-with-node?utm_source=Web%20Code%20Geeks&#038;utm_medium=Content%20Syndication&#038;utm_campaign=build%20basic%20node%20app\" target=\"_blank\" rel=\"noopener\">Tutorial: Build a Basic CRUD App with Node.js<\/a>\u00a0 was originally published on the Okta developer blog on June 28, 2018.<\/p>\n<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Web Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_source=Web%20Code%20Geeks&#038;utm_medium=Content%20Syndication&#038;utm_campaign=build%20basic%20node%20app\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a> <\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u201cI love writing authentication and authorization code.\u201d ~ No Web Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth. Node.js is eating the world. Many of the largest companies are building more and more of their websites and API services with &hellip;<\/p>\n","protected":false},"author":1264,"featured_media":924,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[153],"class_list":["post-22061","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-node-js","tag-express-js"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Build a CRUD App with Express.js and User Authentication - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Interested to learn more about express.js? Then check out our Tutorial where we Build a fully functional Node.js website!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Build a CRUD App with Express.js and User Authentication - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Interested to learn more about express.js? Then check out our Tutorial where we Build a fully functional Node.js website!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2018-07-02T06:09:35+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-07-13T09:27:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Randall Degges\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Randall Degges\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"26 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/\"},\"author\":{\"name\":\"Randall Degges\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/c8e794de4537292b783d6f151f534fba\"},\"headline\":\"Build a CRUD App with Express.js and User Authentication\",\"datePublished\":\"2018-07-02T06:09:35+00:00\",\"dateModified\":\"2018-07-13T09:27:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/\"},\"wordCount\":3105,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg\",\"keywords\":[\"Express.js\"],\"articleSection\":[\"Node.js\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/\",\"url\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node\",\"name\":\"Build a CRUD App with Express.js and User Authentication - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage\"},\"image\":{\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg\",\"datePublished\":\"2018-07-02T06:09:35+00:00\",\"dateModified\":\"2018-07-13T09:27:34+00:00\",\"description\":\"Interested to learn more about express.js? Then check out our Tutorial where we Build a fully functional Node.js website!\",\"breadcrumb\":{\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/javascript\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Node.js\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/javascript\/node-js\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Build a CRUD App with Express.js and User Authentication\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/c8e794de4537292b783d6f151f534fba\",\"name\":\"Randall Degges\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/aee899105ee2856c68bbb4f0c52e5defc6945c88631ee796979d69d6b148578b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/aee899105ee2856c68bbb4f0c52e5defc6945c88631ee796979d69d6b148578b?s=96&d=mm&r=g\",\"caption\":\"Randall Degges\"},\"sameAs\":[\"https:\/\/developer.okta.com\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/randall-degges\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Build a CRUD App with Express.js and User Authentication - Web Code Geeks - 2026","description":"Interested to learn more about express.js? Then check out our Tutorial where we Build a fully functional Node.js website!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node","og_locale":"en_US","og_type":"article","og_title":"Build a CRUD App with Express.js and User Authentication - Web Code Geeks - 2026","og_description":"Interested to learn more about express.js? Then check out our Tutorial where we Build a fully functional Node.js website!","og_url":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_published_time":"2018-07-02T06:09:35+00:00","article_modified_time":"2018-07-13T09:27:34+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg","type":"image\/jpeg"}],"author":"Randall Degges","twitter_card":"summary_large_image","twitter_creator":"@webcodegeeks","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Randall Degges","Est. reading time":"26 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/"},"author":{"name":"Randall Degges","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/c8e794de4537292b783d6f151f534fba"},"headline":"Build a CRUD App with Express.js and User Authentication","datePublished":"2018-07-02T06:09:35+00:00","dateModified":"2018-07-13T09:27:34+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/"},"wordCount":3105,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg","keywords":["Express.js"],"articleSection":["Node.js"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/javascript\/node-js\/crud-app-express-js-user-authentication\/","url":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node","name":"Build a CRUD App with Express.js and User Authentication - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg","datePublished":"2018-07-02T06:09:35+00:00","dateModified":"2018-07-13T09:27:34+00:00","description":"Interested to learn more about express.js? Then check out our Tutorial where we Build a fully functional Node.js website!","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/nodejs-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2018\/02\/15\/build-crud-app-vuejs-node#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"JavaScript","item":"https:\/\/www.webcodegeeks.com\/category\/javascript\/"},{"@type":"ListItem","position":3,"name":"Node.js","item":"https:\/\/www.webcodegeeks.com\/category\/javascript\/node-js\/"},{"@type":"ListItem","position":4,"name":"Build a CRUD App with Express.js and User Authentication"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/c8e794de4537292b783d6f151f534fba","name":"Randall Degges","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/aee899105ee2856c68bbb4f0c52e5defc6945c88631ee796979d69d6b148578b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/aee899105ee2856c68bbb4f0c52e5defc6945c88631ee796979d69d6b148578b?s=96&d=mm&r=g","caption":"Randall Degges"},"sameAs":["https:\/\/developer.okta.com"],"url":"https:\/\/www.webcodegeeks.com\/author\/randall-degges\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/22061","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/1264"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=22061"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/22061\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/924"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=22061"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=22061"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=22061"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}