<?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: Brandon Parise</title>
    <description>The latest articles on DEV Community by Brandon Parise (@bparise).</description>
    <link>https://dev.to/bparise</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%2F75768%2Fc22b3180-1820-42a5-bb32-904fa3704345.jpeg</url>
      <title>DEV Community: Brandon Parise</title>
      <link>https://dev.to/bparise</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bparise"/>
    <language>en</language>
    <item>
      <title>The Death of Coding Bootcamps?</title>
      <dc:creator>Brandon Parise</dc:creator>
      <pubDate>Tue, 14 May 2019 20:34:33 +0000</pubDate>
      <link>https://dev.to/bparise/the-death-of-coding-bootcamps-p6i</link>
      <guid>https://dev.to/bparise/the-death-of-coding-bootcamps-p6i</guid>
      <description>&lt;p&gt;In recent years, coding bootcamps have been one of the most trendy ways to learn to program. These courses can condense years of practical learning into a short period of time and often put graduates on an upwards career path.&lt;/p&gt;

&lt;p&gt;But in recent years, several coding bootcamps have shut their doors. Why were these bootcamps so appealing in the first place? Why are they closing? And what does the future of programming instruction look like?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Bootcamps?
&lt;/h2&gt;

&lt;p&gt;Coding is an essential skill in many segments of the tech world, and can be an entry point to a lucrative career. However, many traditional instructional models are insufficient when applied to learning to code.&lt;br&gt;
Many high schools and colleges treat coding like just another educational topic, to be mastered over the course of a semester or two. However, in many ways, coding is more like a skilled trade than a liberal art. Mastery is not based on what a coder understands, but on what they can do.&lt;/p&gt;

&lt;p&gt;This is why many students have found coding bootcamps appealing. They shore up many of the weaknesses of traditional instructional models by focusing on function rather than theory, and helping students rapidly acquire skills.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bursting Bubble
&lt;/h2&gt;

&lt;p&gt;2017 saw the closure of two prominent coding bootcamps: Kaplan's Dev Bootcamp, and Apollo Education Group's Iron Yard. The period between then and now (mid-2019) has seen even more closures of bootcamps, both small and large.&lt;/p&gt;

&lt;p&gt;This has taken several industry experts by surprise. For a while, coding bootcamps looked unassailable. Now, even established operations are folding. Industry experts have several competing theories about what's happening.&lt;/p&gt;

&lt;p&gt;The first is that there are too many coding bootcamps, and not enough students to fill them. However, it's unclear which end of the equation is most responsible. It's undeniable that recent years have seen a tremendous number of coding bootcamps open their doors, and it's possible supply outstrips demand.&lt;/p&gt;

&lt;p&gt;But it's also possible that industry analysts have seriously overestimated the demand. There may not be as many open jobs as analysts think. Coding may not be as essential as received wisdom says, or workers may not yet be fully facing economic realities.&lt;/p&gt;

&lt;p&gt;Finally, it's also possible that potential coders are realizing coding bootcamps don't provide the skills or experience they need. Many people may feel their skills are better reinforced in a classroom setting, or with more experience gained slowly, over time. Alternately, employers may be reluctant to hire a graduate from a coding bootcamp, compared with an applicant with a computer science degree.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Coding Instruction
&lt;/h2&gt;

&lt;p&gt;With so many coding bootcamps going under, many instructors and entrepreneurs are wondering what's next.&lt;/p&gt;

&lt;p&gt;While some camps may be closing, that doesn't mean the bootcamp model has no future. Many students will probably still seek out the valuable experiences coding bootcamps can offer.&lt;/p&gt;

&lt;p&gt;Many companies may reform the coding bootcamp business model. When Kaplan closed Dev Bootcamp, it cited high overhead as a factor. Coding bootcamps require paying experts for their intensive attention over several weeks. It's likely companies will develop more cost-effective instructional models. It's also likely federal workforce development subsidies would make bootcamps more financially sustainable.&lt;/p&gt;

&lt;p&gt;Finally, it's possible many potential students will seek out slower, more intensive models of instruction. While this doesn't have the same near-instant gratification as a coding bootcamp, it reinforces ideas learned over time and cultivates greater skill and versatility. Changing the instructional model may also allow instructors to give students more individualized attention -- something coding bootcamps have generally eschewed in favor of a one-size-fits-all approach.&lt;/p&gt;

&lt;p&gt;The coding bootcamp industry isn't dead, but it is suffering. With several recent closures of high-profile bootcamps, industry experts are working to diagnose and address the problem. It's unclear what the future will hold, but it's likely students will see a proliferation of more financially-sustainable educational models that focus on more in-depth instruction.&lt;/p&gt;

&lt;p&gt;Sources&lt;br&gt;
&lt;a href="http://hackeducation.com/2017/07/22/bootcamp-bust"&gt;http://hackeducation.com/2017/07/22/bootcamp-bust&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.edsurge.com/news/2017-08-03-coding-boot-camps-won-t-save-us-all"&gt;https://www.edsurge.com/news/2017-08-03-coding-boot-camps-won-t-save-us-all&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>education</category>
    </item>
    <item>
      <title>I have been a TopTal Software Engineer for two years, Ask Me Anything!</title>
      <dc:creator>Brandon Parise</dc:creator>
      <pubDate>Fri, 05 Apr 2019 18:48:24 +0000</pubDate>
      <link>https://dev.to/bparise/i-have-been-a-toptal-software-engineer-for-two-years-ask-me-anything-2e9k</link>
      <guid>https://dev.to/bparise/i-have-been-a-toptal-software-engineer-for-two-years-ask-me-anything-2e9k</guid>
      <description>&lt;p&gt;With a strong tailwind of practical experience, tremendous passion, and a newborn baby I founded my company &lt;a href="https://modernup.io/"&gt;ModernUp&lt;/a&gt; in 2015 with one goal in mind: to help startups and early growth-stage companies get to market fast.&lt;/p&gt;

&lt;p&gt;However, keeping my schedule full (and money coming in the door) became an early  challenge. I worked hard on finding unique ways to work with new clients, and came across &lt;a href="https://www.toptal.com/#explore-exclusively-perfect-software-architect-experts"&gt;TopTal&lt;/a&gt; while browsing LinkedIn.&lt;/p&gt;

&lt;p&gt;Shortcut to two years later and I've booked thousands of hours with &lt;a href="https://www.toptal.com/#explore-exclusively-perfect-software-architect-experts"&gt;TopTal&lt;/a&gt; across multiple projects. Ask away!&lt;/p&gt;

</description>
      <category>ama</category>
    </item>
    <item>
      <title>Deploy Your Secure Vue.js App to AWS</title>
      <dc:creator>Brandon Parise</dc:creator>
      <pubDate>Tue, 03 Jul 2018 05:00:00 +0000</pubDate>
      <link>https://dev.to/oktadev/deploy-your-secure-vuejs-app-to-aws-5g5</link>
      <guid>https://dev.to/oktadev/deploy-your-secure-vuejs-app-to-aws-5g5</guid>
      <description>&lt;p&gt;Writing a Vue app is intuitive, straightforward, and fast. With low barriers to entry, a component-based approach, and built-in features like hot reloading and webpack, Vue allows you to focus on developing your application rather than worrying about your dev environment and build processes. But, what happens when you are ready to deploy your app into production? The choices can be endless and sometimes unintuitive.&lt;/p&gt;

&lt;p&gt;As an AWS Certified Solutions Architect, I am frequently asked how to deploy Vue apps to AWS. In this tutorial, I will walk you through building a small, secure Vue app and deploying it to Amazon Web Services (AWS). If you’ve never used AWS, don’t worry! I’ll walk you through each step of the way starting with creating an AWS account.&lt;/p&gt;

&lt;h2&gt;
  
  
  About AWS
&lt;/h2&gt;

&lt;p&gt;Amazon Web Services (AWS) is a cloud platform that provides numerous &lt;a href="https://aws.amazon.com/products/" rel="noopener noreferrer"&gt;on-demand cloud services&lt;/a&gt;. These services include cloud computing, file storage, relational databases, a content distribution network, and many, many more. AWS came into existence not as a retail offering, but rather Amazon’s internal answer to the growing complexity of the infrastructure that was responsible for powering Amazon.com and their e-commerce operations. Amazon quickly realized their cloud-based infrastructure was a compelling, cost-effective solution and opened it to the public in 2006.&lt;/p&gt;

&lt;p&gt;At the time of writing this article, AWS is worth an estimated &lt;a href="https://seekingalpha.com/article/4140036-much-amazon-web-services-worth-now" rel="noopener noreferrer"&gt;$250B&lt;/a&gt; (yes, that’s a B for BILLION) and used by thousands of companies and developers worldwide.&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%2Fvue-aws%2Faws-vue-aws-services-f3354108f66c27351ccccb6ca56b01a402de9ce59e2e9f7c9640dfd4612f7e1b.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%2Fvue-aws%2Faws-vue-aws-services-f3354108f66c27351ccccb6ca56b01a402de9ce59e2e9f7c9640dfd4612f7e1b.png" alt="AWS Products"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Will Build
&lt;/h2&gt;

&lt;p&gt;I feel the best way to learn is by doing. I’ll walk you through building a small, Vue app with an Express REST server. You will secure your app using &lt;a href="https://developer.okta.com/docs/api/resources/oidc" rel="noopener noreferrer"&gt;Okta’s OpenID Connect (OIDC)&lt;/a&gt; which enables user authentication and authorization with just a few lines of code.&lt;/p&gt;

&lt;p&gt;You will begin by building the Vue frontend and deploy it to Amazon S3. Then you will leverage Amazon CloudFront to distribute your Vue frontend to edge servers all around the world. Lastly, you will create an Express API server and deploy it with &lt;a href="https://serverless.com/" rel="noopener noreferrer"&gt;Serverless&lt;/a&gt;. This API server will contain a method to fetch “secure data” (just some dummy data) which requires a valid access token from the client to retrieve.&lt;/p&gt;

&lt;p&gt;The goal of this article is to show you how to leverage multiple AWS services rather than just spinning up a single EC2 instance to serve your app. With this services-based approach, you have a limitless scale, zero maintenance, and a cost-effective way to deploy apps in the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Okta?
&lt;/h2&gt;

&lt;p&gt;Okta is a cloud service that allows developers to manage user authentication and connect them with one or multiple applications. The Okta API enables you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.okta.com/product/authentication/" rel="noopener noreferrer"&gt;Authenticate&lt;/a&gt; and &lt;a href="https://developer.okta.com/product/authorization/" rel="noopener noreferrer"&gt;authorize&lt;/a&gt; your users&lt;/li&gt;
&lt;li&gt;Store data about your users&lt;/li&gt;
&lt;li&gt;Perform password-based and &lt;a href="https://developer.okta.com/authentication-guide/social-login/" rel="noopener noreferrer"&gt;social login&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Secure your application with &lt;a href="https://developer.okta.com/use_cases/mfa/" rel="noopener noreferrer"&gt;multi-factor authentication&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;And much more! Check out our &lt;a href="https://developer.okta.com/documentation/" rel="noopener noreferrer"&gt;product documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;Register for a free developer account&lt;/a&gt;, and when you’re done, come on back so we can learn more deploying a Vue app to AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrap Frontend
&lt;/h2&gt;

&lt;p&gt;You are going to build the Vue frontend to your secure app first and deploy it to Amazon S3 and Amazon CloudFront. Amazon S3 (Simple Storage Service) is a highly redundant, object-based file store that is both powerful and &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#S3Features" rel="noopener noreferrer"&gt;featureful&lt;/a&gt;. In the scope of this article, we will focus on one of the best features S3 provides: Static website hosting.&lt;/p&gt;

&lt;p&gt;To get started quickly, you can use the scaffolding functionality from &lt;a href="https://github.com/vuejs/vue-cli" rel="noopener noreferrer"&gt;vue-cli&lt;/a&gt; to get your app up and running quickly. For this article, you can use the &lt;a href="https://github.com/vuejs-templates/webpack" rel="noopener noreferrer"&gt;webpack template&lt;/a&gt; that includes hot reloading, CSS extraction, linting, and integrated build tools.&lt;/p&gt;

&lt;p&gt;To install &lt;code&gt;vue-cli&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 vue-cli@2.9.6

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

&lt;/div&gt;



&lt;p&gt;Next up is to initialize your project. When you run the following &lt;code&gt;vue init&lt;/code&gt; command, accept all the default values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vue init webpack secure-app-client
cd ./secure-app-client
npm run dev

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

&lt;/div&gt;



&lt;p&gt;The init method should also install your app’s dependencies. If for some reason it doesn’t, you can install them via &lt;code&gt;npm install&lt;/code&gt;. Finally, open your favorite browser and navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt;. You should see the frontend come alive!&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%2Fvue-aws%2Faws-vue-2-3b599d0abb7e513ff101f9ae7c1f1d221b709c60b704272c451938b5dfbde9c5.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%2Fvue-aws%2Faws-vue-2-3b599d0abb7e513ff101f9ae7c1f1d221b709c60b704272c451938b5dfbde9c5.png" alt="Welcome to Your Vue.js App"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Single Page Applications
&lt;/h2&gt;

&lt;p&gt;When you create an application with Vue, you are developing a Single Page Application (or “SPA”). SPAs have numerous advantages over traditional multi-page, server-rendered apps. It’s important to understand the difference between SPAs and multi-page web applications — especially when it comes to deploying.&lt;/p&gt;

&lt;p&gt;A SPA app is often referred as a “static app” or “static website.” Static, in this context, means that your application compiles all its code to static assets (HTML, JS, and CSS). With these static assets, there is no specialized web server required to serve the application to your users.&lt;/p&gt;

&lt;p&gt;Traditional web applications require a specialized web server to render every request to a client. For each of these requests, the entire payload of a page (including static assets) is transferred.&lt;/p&gt;

&lt;p&gt;Conversely, within an SPA there is only an initial request for the static files, and then JavaScript dynamically rewrites the current page. As your users are navigating your app, requests to subsequent pages are resolved locally and don’t require an HTTP call to a server.&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%2Fvue-aws%2Faws-vue-3-0a209e13e3a4db06c3b4f2b833fb872475de7413aa8dcc5c2e7c74bcda327afa.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%2Fvue-aws%2Faws-vue-3-0a209e13e3a4db06c3b4f2b833fb872475de7413aa8dcc5c2e7c74bcda327afa.png" alt="SPA versus Traditional Web Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Vue-router and Creating Additional Routes
&lt;/h2&gt;

&lt;p&gt;The component of an SPA that is required to rewrite the current page dynamically is commonly referred to as a “router”. The router programmatically calculates which parts of the page should mutate based off the path in the URL.&lt;/p&gt;

&lt;p&gt;Vue has an official router that is aptly named &lt;a href="https://router.vuejs.org/" rel="noopener noreferrer"&gt;vue-router&lt;/a&gt;. Since you used the vue-cli bootstrap, your app has this dependency and a router file defined (&lt;code&gt;./src/router/index.js&lt;/code&gt;). Before we can define additional routes, we need to create the pages (or components) that you want the router to render. Create the following files in your project:&lt;/p&gt;

&lt;p&gt;Homepage: &lt;code&gt;./src/components/home.vue&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Home&amp;lt;/h1&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;router-link to="/secure"&amp;gt;Go to secure page&amp;lt;/router-link&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Secure Page (not secured… yet!) &lt;code&gt;./src/components/secure.vue&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Secure Page&amp;lt;/h1&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;router-link to="/"&amp;gt;Go back&amp;lt;/router-link&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Using &lt;a href="https://router.vuejs.org/" rel="noopener noreferrer"&gt;vue-router&lt;/a&gt;, you can inform the application to render each page based on the path.&lt;/p&gt;

&lt;p&gt;Modify &lt;code&gt;./src/router/index.js&lt;/code&gt; to match the following code snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/home'
import Secure from '@/components/secure'

Vue.use(Router)

let router = new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/secure',
      name: 'Secure',
      component: Secure
    }
  ]
})

export default router

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

&lt;/div&gt;



&lt;p&gt;Try it out! Tab back to your browser, and you should see the new home screen. If you click on the “Go to secure page” link you will notice the page (and URL) change, but no request was sent to a server!&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand Hash History
&lt;/h2&gt;

&lt;p&gt;As you navigated between the two pages above, you might have seen that the URL looks different than expected (do you noticed the “#/” at the beginning of the path?)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://localhost:8080/#/&lt;/code&gt; and &lt;code&gt;http://localhost:8080/#/secure&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The reason the URL looks like is because vue-router’s default mode is &lt;em&gt;hash mode&lt;/em&gt;. Hash mode simulates a new URL change without instructing the browser to reload the page. This behavior is what allows SPA’s to navigate pages without forcing your browser to make any additional HTTP requests. Vue-router listens for changes in the hash portion of the URL (everything after the “#”) and responds accordingly based on the routes configured.&lt;/p&gt;

&lt;p&gt;You can change the mode of vue-router to leverage &lt;em&gt;history mode&lt;/em&gt; which will give your app “pretty URLs” like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;http://localhost:8080/secure&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But, this comes with a significant drawback — especially when you are deploying. Since your SPA compiles to a static assets, there is just one single entry point &lt;code&gt;index.html&lt;/code&gt;. If you try to access a page direction that is not &lt;code&gt;index.html&lt;/code&gt; page (i.e.; &lt;code&gt;http://localhost:8080/secure&lt;/code&gt;) the web server will return a 404 error. &lt;em&gt;Why&lt;/em&gt;? The browser is sending a GET &lt;code&gt;/secure&lt;/code&gt; request to the server and trying to resolve to the filesystem “/secure” (and the file doesn’t exist). It does work when you navigate to &lt;code&gt;/secure&lt;/code&gt; from the homepage because vue-router prevents the default behavior of the browsers and instructs the router instance to fire in any mode.&lt;/p&gt;

&lt;p&gt;By using history mode, you have to take additional steps to make sure page refreshes work correctly. You can read more about &lt;a href="https://router.vuejs.org/guide/essentials/history-mode.html#html5-history-mode" rel="noopener noreferrer"&gt;HTML5 History Mode&lt;/a&gt;. To keep things easy, I will show you a simple trick to ensure your refreshing works with AWS CloudFront.&lt;/p&gt;

&lt;p&gt;Enable history mode by modifying &lt;code&gt;./router/index.js&lt;/code&gt; with the following setting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let router = new Router({
  mode: 'history',
})

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The dev server (&lt;code&gt;npm run dev&lt;/code&gt;) automatically rewrites the URL to &lt;code&gt;index.html&lt;/code&gt; for you. So the behavior you see locally is how it should work in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your Single Page Application
&lt;/h2&gt;

&lt;p&gt;Now that you have a simple, two-page frontend working locally, it’s time to build your app and get it deployed to AWS!&lt;/p&gt;

&lt;p&gt;Because you used vue-cli scaffolding, a single call to the included build script is all you need. From your project root, run &lt;code&gt;npm run build&lt;/code&gt; and webpack will build your application into the target &lt;code&gt;./dist&lt;/code&gt; directory. If the dev server is still running in your console, you can press CTRL+C.&lt;/p&gt;

&lt;p&gt;If you open the &lt;code&gt;./dist&lt;/code&gt; folder and you should see the results of the build process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;./index.html&lt;/code&gt; - This is the entry point of your SPA. It’s a minified HTML document with links to the apps CSS and JS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./static&lt;/code&gt; - This folder contains all your compiled static assets (JS and CSS)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During the build, you might have noticed the following notification: &lt;strong&gt;Tip: built files are meant to be served over an HTTP server. Opening index.html over file:// won’t work&lt;/strong&gt;. If you want to test your newly compiled application locally, you can use &lt;code&gt;serve&lt;/code&gt; (install via &lt;code&gt;npm install -g serve&lt;/code&gt;). Run &lt;code&gt;serve ./dist&lt;/code&gt; and it will output a URL for you to load into your browser.&lt;/p&gt;

&lt;p&gt;This also gives you to have a hands-on experience with the major caveat of history mode with vue-router. After running &lt;code&gt;serve ./dist&lt;/code&gt;, click on the “Go to secure page”. You should see a 404 error.&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%2Fvue-aws%2Faws-vue-4-4e2d642816a7f7e0dc0cdfd5b8fed1775a577dceb7fc83dce9f9fa424625975b.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%2Fvue-aws%2Faws-vue-4-4e2d642816a7f7e0dc0cdfd5b8fed1775a577dceb7fc83dce9f9fa424625975b.png" alt="404 Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with AWS
&lt;/h2&gt;

&lt;p&gt;You will need an AWS account to continue beyond this point. If you already have an AWS account, you can skip ahead. If you don’t, it’s a simple process that only takes a few minutes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the &lt;a href="https://aws.amazon.com" rel="noopener noreferrer"&gt;Amazon Web Services home page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Sign Up&lt;/strong&gt; (or if you have signed into AWS recently choose &lt;strong&gt;Sign In to the Console&lt;/strong&gt; )&lt;/li&gt;
&lt;li&gt;If prompted, you can select “Personal” for account type&lt;/li&gt;
&lt;li&gt;Complete the required information, add a payment method, and verify your phone number&lt;/li&gt;
&lt;li&gt;After your account is created, you should receive a confirmation email&lt;/li&gt;
&lt;li&gt;Log in!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; Amazon requires you to enter a payment method before you can create your account. All the services discussed in this article are covered under &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;AWS Free Tier&lt;/a&gt; which gives you 12 months FREE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Host Your App on Amazon S3
&lt;/h2&gt;

&lt;p&gt;Since your SPA is comprised of only static assets, we can leverage Amazon S3 (Simple Storage Service) to store and serve your files.&lt;/p&gt;

&lt;p&gt;To get started, you will need to create a bucket. Buckets are a logical unit of storage within S3, and you can have up to 100 buckets per AWS account by default (if you are studying for the AWS Certified Solutions Architect exam, you should know this!). Each bucket can have its own configuration and contain unlimited files and nested folders.&lt;/p&gt;

&lt;p&gt;After you log in to your AWS Console, navigate to the S3 console (you can do this under AWS services search for “S3”).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click “Create Bucket” and enter a Bucket name. &lt;strong&gt;&lt;em&gt;Important&lt;/em&gt;&lt;/strong&gt; : Bucket names are unique across the entire AWS platform. I chose &lt;code&gt;bparise-secure-app-client&lt;/code&gt; for this article, but you might need to be creative with your naming!&lt;/li&gt;
&lt;li&gt;Click “Create” in the bottom left.&lt;/li&gt;
&lt;/ul&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%2Fvue-aws%2Faws-vue-create-bucket-a5ffc62fd50b798e0aacc01e348f4b2e9b0b39b6166406125258ffb2cd067165.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%2Fvue-aws%2Faws-vue-create-bucket-a5ffc62fd50b798e0aacc01e348f4b2e9b0b39b6166406125258ffb2cd067165.png" alt="Create S3 Bucket"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should now see your bucket listed. Next, let’s configure it for static website hosting.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click your Bucket name and then choose the “Properties” tab.&lt;/li&gt;
&lt;li&gt;Click on “Static website hosting” box&lt;/li&gt;
&lt;li&gt;Choose “Use this bucket to host a website” and add “index.html” as the index document. Click “Save”.&lt;/li&gt;
&lt;/ul&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%2Fvue-aws%2Faws-vue-5-c1c882a4a2c6234f4458ada7b1a93e9f54def19f77668363fe17d92284914413.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%2Fvue-aws%2Faws-vue-5-c1c882a4a2c6234f4458ada7b1a93e9f54def19f77668363fe17d92284914413.png" alt="Static website hosting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the top of the Static website hosting box, you should see a URL for “Endpoint”. This is the publicly accessible URL to view your static website. Open the link into a new browser window, and you should see 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%2Fvue-aws%2Faws-vue-6-695d376b9163579abc838bd663abfcddbf34fee2f48a42c157a3bf5f13cd4341.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%2Fvue-aws%2Faws-vue-6-695d376b9163579abc838bd663abfcddbf34fee2f48a42c157a3bf5f13cd4341.png" alt="403 Forbidden"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Access Denied and S3 Bucket Policies
&lt;/h4&gt;

&lt;p&gt;Yes, you should see a 403 Forbidden error! By default, S3 bucket permissions are &lt;em&gt;deny all&lt;/em&gt;. To access your bucket’s contents, you must explicitly define who can access your bucket. These bucket permissions are called a Bucket Policy.&lt;/p&gt;

&lt;p&gt;To add a Bucket Policy, click on the “Permissions” tab and click “Bucket Policy” button at the top. The following policy allows anyone to read any file in your bucket. Make sure to replace “YOUR-BUCKET-NAME” with your actual bucket name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadAccess",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
        }
    ]
}

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

&lt;/div&gt;



&lt;p&gt;Bucket Policies can be quite complex and powerful. But, the main parts of the policy that you should be aware of are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;"Effect": "Allow"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"Principal": "*"&lt;/code&gt; - Who the policy covers (“*” implies everyone)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"Action": "s3:GetObject"&lt;/code&gt; - The action allowed (s3:GetObject allows read-only access to all objects in your bucket)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"&lt;/code&gt; - Which bucket and objects the policy is about.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click “Save” on the Bucket Policy editor. You should notice a new error is displayed if you set up the policy correctly:&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%2Fvue-aws%2Faws-vue-8-868ab6f4049d3c34e9b56032e678b2bdb784bbec76a95d67507b6980b79f3874.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%2Fvue-aws%2Faws-vue-8-868ab6f4049d3c34e9b56032e678b2bdb784bbec76a95d67507b6980b79f3874.png" alt="This bucket has public access"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This warning is good advice and a rule of thumb for all S3 buckets. But, since our bucket is exclusively used to host a static website, we don’t have to worry about anyone accessing a file within the bucket they shouldn’t.&lt;/p&gt;

&lt;p&gt;Tab back to your browser and refresh the endpoint. You should now see a 404 Not Found error. This error is much easier to resolve because you don’t have any files in your bucket yet.&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%2Fvue-aws%2Faws-vue-9-2f229a3c2e4316c75d8ac17205baf6f51fc94cb6aa1d535967e6d37ffc81a8c1.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%2Fvue-aws%2Faws-vue-9-2f229a3c2e4316c75d8ac17205baf6f51fc94cb6aa1d535967e6d37ffc81a8c1.png" alt="404 index.html not found"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy to AWS with aws-cli
&lt;/h2&gt;

&lt;p&gt;Now that you have a bucket created and permissions correctly set, it’s time to upload your static assets. Although you can do this manually through the interface by using the “Upload” button, I feel using the &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;aws-cli&lt;/a&gt; is more efficient.&lt;/p&gt;

&lt;p&gt;Installing &lt;code&gt;asw-cli&lt;/code&gt; is different based on your OS. Choose one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows: &lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;https://aws.amazon.com/cli/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Mac/linux run &lt;code&gt;pip install awscli&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you’ve installed &lt;code&gt;aws-cli&lt;/code&gt;, you will need to generate keys within AWS so you can perform actions via the CLI.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose your account name in the navigation bar, and then choose My Security Credentials. (If you see a warning about accessing the security credentials for your AWS account, choose Continue to Security Credentials.)&lt;/li&gt;
&lt;li&gt;Expand the Access keys (access key ID and secret access key) section.&lt;/li&gt;
&lt;li&gt;Choose Create New Access Key. A warning explains that you have only this one opportunity to view or download the secret access key. It cannot be retrieved later.&lt;/li&gt;
&lt;li&gt;If you choose Show Access Key, you can copy the access key ID and secret key from your browser window and paste it somewhere else.&lt;/li&gt;
&lt;li&gt;If you choose Download Key File, you receive a file named &lt;code&gt;rootkey.csv&lt;/code&gt; that contains the access key ID and the secret key. Save the file somewhere safe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: If you had an existing AWS account or are not using root credentials. You can view and generate your keys in IAM.&lt;/p&gt;

&lt;p&gt;Now that you have your Access Key and Secret Access Key, you need to configure the cli. In your console run &lt;code&gt;aws configure&lt;/code&gt; and paste in your keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws configure
AWS Access Key ID [None]: YOUR KEY
AWS Secret Access Key [None]: YOUR SECRET
Default region name [None]: us-east-1
Default output format [None]: ENTER

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

&lt;/div&gt;



&lt;p&gt;Now, you can use the &lt;code&gt;aws-cli&lt;/code&gt; to sync your &lt;code&gt;./dist&lt;/code&gt; folder to your new bucket. Syncing will diff what’s in your &lt;code&gt;./dist&lt;/code&gt; folder with what’s in the bucket and only upload the required changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 sync ./dist s3://your-bucket-name

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

&lt;/div&gt;



&lt;p&gt;Tab back to your S3 bucket endpoint, and you should see your site hosted on S3!&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%2Fvue-aws%2Faws-vue-10-8999e46b88d1e6624a4ff379427e6e4539dcb485e4406812e81d5b5c5ecdfd71.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%2Fvue-aws%2Faws-vue-10-8999e46b88d1e6624a4ff379427e6e4539dcb485e4406812e81d5b5c5ecdfd71.png" alt="Vue.js on S3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For convenience, add the following script entry to &lt;code&gt;package.json&lt;/code&gt; so you can run &lt;code&gt;npm run deploy&lt;/code&gt; when you want to sync your files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
  "deploy": "aws s3 sync ./dist s3://your-bucket-name"
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Distribute your App with Amazon CloudFront CDN
&lt;/h2&gt;

&lt;p&gt;Amazon S3 static web hosting has ultra-low latency if you are geographically near the region your bucket is hosted in. But, you want to make sure all users can access your site quickly regardless of where they are located. To speed up delivery of your site, you can AWS CloudFront CDN.&lt;/p&gt;

&lt;p&gt;CloudFront is a global content delivery network (CDN) that securely delivers content (websites, files, videos, etc) to users around the globe. At the time of writing this article, CloudFront supports over 50 edge locations:&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%2Fvue-aws%2Faws-vue-11-0c4ee34a848353bfdbfefe5177c30dfd0c05f94d5d4f61e5b8c48b22b0173f0a.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%2Fvue-aws%2Faws-vue-11-0c4ee34a848353bfdbfefe5177c30dfd0c05f94d5d4f61e5b8c48b22b0173f0a.png" alt="CloudFront Locations"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Setting up a CloudFront Distribution takes just a few minutes now that your files are stored in S3.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="https://console.aws.amazon.com/cloudfront/home" rel="noopener noreferrer"&gt;CloudFront Home&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Distribution&lt;/strong&gt; , and select &lt;strong&gt;Get Started&lt;/strong&gt; under Web settings&lt;/li&gt;
&lt;li&gt;In the “Origin Domain Name” you should see your bucket name in the drop-down. Select that bucket and make the following changes:&lt;/li&gt;
&lt;li&gt;Viewer Protocol Policy: “Redirect HTTP to HTTPS”. (This is a secure app, right!?)&lt;/li&gt;
&lt;li&gt;Object Caching: “Customize”. And set Minimum TTL and Default TTL both to “0”. You can adjust this later to maximize caching. But, having it at “0” allows us to deploy changes and quickly see them.&lt;/li&gt;
&lt;li&gt;Default Root Object: “index.html”&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The process can take anywhere from 5-15 minutes to fully provision your distribution.&lt;/p&gt;

&lt;p&gt;While you wait, you need to configure your distribution to handle vue-router’s history mode. Click on the ID of your new distribution and click the “Error Page” tab. Add the following error pages.&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%2Fvue-aws%2Faws-vue-1-b91c1744fddb9b2bf0ab94e3852ce891eb55538b2211d26777c78933df4b18af.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%2Fvue-aws%2Faws-vue-1-b91c1744fddb9b2bf0ab94e3852ce891eb55538b2211d26777c78933df4b18af.png" alt="CloudFront Error Redirects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These error page configurations will instruct CloudFront to respond to any 404/403 with &lt;code&gt;./index.html&lt;/code&gt;. Voila!&lt;/p&gt;

&lt;p&gt;Click on the “General” tab, and you should see an entry for “Domain Name”. The Domain Name is the publicly accessible URL for your distribution. After the status of your new distribution is Deployed, paste the URL into your browser.&lt;/p&gt;

&lt;p&gt;Test to make sure the history mode works by navigating to the secure page and refreshing your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authentication with Okta
&lt;/h2&gt;

&lt;p&gt;To use Okta, you must first have an Okta developer account. If you don’t have one you can &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt;. After you are logged in, click “Applications” in the navbar and then “Add Application” button. Make sure to select “Single-Page App” as the platform and click Next.&lt;/p&gt;

&lt;p&gt;You will need to add your CloudFront URL to both Base URIs and also as a Login redirect URIs, otherwise Okta will not allow you to authenticate. Your application settings should look similar to this (except for your CloudFront URL).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Make sure to use HTTPS when entering your CloudFront URL.&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%2Fvue-aws%2Faws-vue-13-77fb3edeab511e863be11ac8d61e7ba759ffe574ee4010ebf3896cbfbbe63cd9.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%2Fvue-aws%2Faws-vue-13-77fb3edeab511e863be11ac8d61e7ba759ffe574ee4010ebf3896cbfbbe63cd9.png" alt="Okta Application Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of your “Client ID” at the bottom of the “General” tab as you will need it to configure your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Secure Authentication to Your App
&lt;/h2&gt;

&lt;p&gt;Okta has a handy Vue component to handle all the heavy lifting of integrating with their services. To install the Okta Vue SDK, run 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;npm i @okta/okta-vue@1.0.1

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

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;src/router/index.js&lt;/code&gt; and modify it to look like the following code. Also, make sure to change &lt;code&gt;{yourClientId}&lt;/code&gt; and &lt;code&gt;{yourOktaDomain}&lt;/code&gt; to yours!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/home'
import Secure from '@/components/secure'
import Auth from '@okta/okta-vue'

Vue.use(Auth, {
  issuer: 'https://{yourOktaDomain}/oauth2/default',
  client_id: '{yourClientId}',
  redirect_uri: window.location.origin + '/implicit/callback',
  scope: 'openid profile email'
})

Vue.use(Router)

let router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home
    },
    {
      path: '/implicit/callback',
      component: Auth.handleCallback()
    },
    {
      path: '/secure',
      name: 'Secure',
      component: Secure,
      meta: {
        requiresAuth: true
      }
    }
  ]
})

router.beforeEach(Vue.prototype.$auth.authRedirectGuard())

export default router

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

&lt;/div&gt;



&lt;p&gt;Next is to lock down the &lt;code&gt;/secure&lt;/code&gt; route to only authenticated users. Okta’s Vue SDK comes with the method &lt;code&gt;auth.authRedirectGuard()&lt;/code&gt; that inspects your routes metadata for the key &lt;code&gt;requiresAuth&lt;/code&gt; and redirects unauthenticated users to Okta’s authentication flow.&lt;/p&gt;

&lt;p&gt;Finally, make some style changes to &lt;code&gt;App.vue&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;template&amp;gt;
  &amp;lt;div id="app"&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;a href="#" v-if="!activeUser" @click.prevent="login"&amp;gt;Login&amp;lt;/a&amp;gt;
      &amp;lt;div v-else&amp;gt;
        Welcome - &amp;lt;a href="#" @click.prevent="logout"&amp;gt;Logout&amp;lt;/a&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;router-view/&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
  export default {
    name: 'app',
    data () {
      return {
        activeUser: null
      }
    },
    async created () {
      await this.refreshActiveUser()
    },
    watch: {
      // everytime a route is changed refresh the activeUser
      '$route': 'refreshActiveUser'
    },
    methods: {
      login () {
        this.$auth.loginRedirect()
      },
      async refreshActiveUser () {
        this.activeUser = await this.$auth.getUser()
      },
      async logout () {
        await this.$auth.logout()
        await this.refreshActiveUser()
        this.$router.push('/')
      }
    }
  }
&amp;lt;/script&amp;gt;

&amp;lt;style&amp;gt;
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
&amp;lt;/style&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;In your terminal, restart the dev server via &lt;code&gt;npm run dev&lt;/code&gt;. Tab to your browser and open &lt;code&gt;http://localhost:8080&lt;/code&gt;. If you click “Login” or “Go to secure page” (the protected &lt;code&gt;/secure&lt;/code&gt; route), you should get Okta’s authentication flow.&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%2Fvue-aws%2Faws-vue-14-4de9c6592c4f072f5ee738fc56334a47da9bc205a8c65a87b9fdb3c355b01ac7.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%2Fvue-aws%2Faws-vue-14-4de9c6592c4f072f5ee738fc56334a47da9bc205a8c65a87b9fdb3c355b01ac7.png" alt="Okta Sign-In"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking either of these should show you as logged in and you should be able to access the Secure Page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a Secure Express REST Server
&lt;/h2&gt;

&lt;p&gt;Finally, we are going to build an &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; server to respond to &lt;code&gt;/hello&lt;/code&gt; and &lt;code&gt;/secure-data&lt;/code&gt; requests. The &lt;code&gt;/secure-data&lt;/code&gt; will be protected and require an authentication token from the frontend. This token is available via &lt;code&gt;$auth.getUser()&lt;/code&gt; thanks to Okta’s Vue SDK.&lt;/p&gt;

&lt;p&gt;To get started, create a new directory for your server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir secure-app-server
cd secure-app-server
npm init -y

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

&lt;/div&gt;



&lt;p&gt;Then install 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 -s express cors body-parser @okta/jwt-verifier aws-serverless-express

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

&lt;/div&gt;



&lt;p&gt;Next is to create a file that will define the application. Copy the following code into &lt;code&gt;app.js&lt;/code&gt; and change &lt;code&gt;{yourClientId}&lt;/code&gt; and &lt;code&gt;{yourOktaDomain}&lt;/code&gt; to yours.&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 cors = require('cors')
const bodyParser = require('body-parser')
const OktaJwtVerifier = require('@okta/jwt-verifier')

const oktaJwtVerifier = new OktaJwtVerifier({
  clientId: '{yourClientId}',
  issuer: 'https://{yourOktaDomain}/oauth2/default'
})

let app = express()
app.use(cors())
app.use(bodyParser.json())

// verify JWT token middleware
const authRequired = () =&amp;gt; {
  return (req, res, next) =&amp;gt; {
    // require request to have an authorization header
    if (!req.headers.authorization) {
      return next(new Error('Authorization header is required'))
    }
    let parts = req.headers.authorization.trim().split(' ')
    let accessToken = parts.pop()
    oktaJwtVerifier.verifyAccessToken(accessToken)
      .then(jwt =&amp;gt; {
        req.user = {
          uid: jwt.claims.uid,
          email: jwt.claims.sub
        }
        next()
      })
      .catch(next) // jwt did not verify!
  }
}

// public route that anyone can access
app.get('/hello', (req, res) =&amp;gt; {
  return res.json({
    message: 'Hello world!'
  })
})

// route uses authRequired middleware to secure it
app.get('/secure-data', authRequired(), (req, res) =&amp;gt; {
  return res.json({
    secret: 'The answer is always "A"!'
  })
})

module.exports = app

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

&lt;/div&gt;



&lt;p&gt;Create one last file that loads up the app and listens on port 8081. Create &lt;code&gt;./index.js&lt;/code&gt; and copy 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 app = require('./app')

app.listen(8081, () =&amp;gt; {
  console.log('listening on 8081')
})

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

&lt;/div&gt;



&lt;p&gt;Start the server by running &lt;code&gt;node ./&lt;/code&gt; in your console. Tab to your browser and open &lt;code&gt;http://localhost:8081/hello&lt;/code&gt;. You should see our JSON payload. But, loading &lt;code&gt;http://localhost:8081/secure-data&lt;/code&gt; should result in an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Call the Secure API Endpoint from Your Vue.js Frontend
&lt;/h3&gt;

&lt;p&gt;With your secure Express REST server still running, navigate back to your client and install axios so you can call the &lt;code&gt;/secure-data&lt;/code&gt; endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i axios

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

&lt;/div&gt;



&lt;p&gt;Modify &lt;code&gt;./src/components/secure.vue&lt;/code&gt; so that it will get the access token from the Okta Vue SDK and send the request to the API.&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;template&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;h1&amp;gt;Secure Page&amp;lt;/h1&amp;gt;
    &amp;lt;h5&amp;gt;Data from GET /secure-data:&amp;lt;/h5&amp;gt;
    &amp;lt;div class="results"&amp;gt;
      &amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;router-link to="/"&amp;gt;Go back&amp;lt;/router-link&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import axios from 'axios'

export default {
  data () {
    return {
      data: null
    }
  },
  async mounted () {
    let accessToken = await this.$auth.getAccessToken()
    const client = axios.create({
      baseURL: 'http://localhost:8081',
      headers: {
        Authorization: `Bearer ${accessToken}`
      }
    })
    let { data } = await client.get('/secure-data')
    this.data = data
  }
}
&amp;lt;/script&amp;gt;

&amp;lt;style&amp;gt;
  .results {
    width: 300px;
    margin: 0 auto;
    text-align: left;
    background: #eee;
    padding: 10px;
  }
&amp;lt;/style&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Tab back to your browser and reload your web app. Navigate to the &lt;code&gt;http://localhost:8080/secure&lt;/code&gt;, and you should see the results from the API call.&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%2Fvue-aws%2Faws-vue-15-399903d818429474627b456f22f6ea56422f3d64706d55a797024092f0126c38.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%2Fvue-aws%2Faws-vue-15-399903d818429474627b456f22f6ea56422f3d64706d55a797024092f0126c38.png" alt="Results of API call"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Serverless and Deploy the Express API
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://serverless.com/" rel="noopener noreferrer"&gt;Serverless&lt;/a&gt; is an open-source AWS Lambda and API Gateway automation framework that allows you to deploy your app into a serverless infrastructure on AWS. The term “serverless” (not to be confused with the software Serverless) is used to describe an app running in the cloud that doesn’t require the developer to provision dedicated servers to run the code.&lt;/p&gt;

&lt;p&gt;Serverless uses &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt; and &lt;a href="https://aws.amazon.com/api-gateway/" rel="noopener noreferrer"&gt;AWS API Gateway&lt;/a&gt; to run your express API 100% in the cloud using only managed services. AWS Lambda is a service that lets you run code in the cloud without provisioning or managing servers. And, AWS API Gateway is a service that makes it easy for developers to create, publish, update, monitor, and secure API’s at scale. Combining both of these services give you a robust platform to host a secure API.&lt;/p&gt;

&lt;p&gt;To get started with Serverless, install it globally.&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 serverless

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

&lt;/div&gt;



&lt;p&gt;Next, you need to create a Serverless configuration in your server app. Use the following command from within your &lt;code&gt;./secure-app-server&lt;/code&gt; project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;serverless create --template aws-nodejs --name secure-app-server

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

&lt;/div&gt;



&lt;p&gt;Open up &lt;code&gt;serverless.yml&lt;/code&gt; and modify it to look like the file below. When you create a Serverless configuration, it contains a lot of boilerplate code and comments. The following structure is all you need to get the app deployed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service: secure-app-server

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev

functions:
  api:
    handler: handler.handler
    events:
      - http: 
          path: "{proxy+}"
          method: ANY
          cors: true

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;provider&lt;/code&gt; spec informs Serverless that your app runs NodeJS and targets deployment on AWS. The &lt;code&gt;functions&lt;/code&gt; outlines a single handler that should handle ANY HTTP requests and forward them your app.&lt;/p&gt;

&lt;p&gt;To finish up Serverless configuration, modify &lt;code&gt;handler.js&lt;/code&gt; to the following code. It uses &lt;a href="https://github.com/awslabs/aws-serverless-express" rel="noopener noreferrer"&gt;aws-serverless-express&lt;/a&gt; which is a neat little package that proxies ALL API requests to a local express app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'use strict';

const awsServerlessExpress = require('aws-serverless-express')
const app = require('./app')
const server = awsServerlessExpress.createServer(app)
exports.handler = (event, context) =&amp;gt; { awsServerlessExpress.proxy(server, event, context) }

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

&lt;/div&gt;



&lt;p&gt;Finally, you should be ready to deploy your app via Serverless. Run 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;serverless deploy

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

&lt;/div&gt;



&lt;p&gt;This process will take a few minutes to provision the stack initially., Once completed, you should see an &lt;code&gt;endpoints&lt;/code&gt; entry under “Service Information” (your URL will be slightly different than mine).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;endpoints:
  ANY - https://YOUR_END_POINT.amazonaws.com/dev/{proxy+}

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

&lt;/div&gt;



&lt;p&gt;To test it out, navigate to &lt;code&gt;https://YOUR_END_POINT.amazonaws.com/dev/hello&lt;/code&gt; and you should see our hello world message. Attempting to go to &lt;code&gt;https://YOUR_END_POINT.amazonaws.com/dev/secure&lt;/code&gt; should result in an error.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change Frontend Vue to Use Production API
&lt;/h3&gt;

&lt;p&gt;Up until this point, your frontend app has been configured to call the API hosted locally on &lt;code&gt;http://localhost:8081&lt;/code&gt;. For production, you need this to be your Serverless Endpoint. Open &lt;code&gt;./src/components/secure.vue&lt;/code&gt; and replace &lt;code&gt;baseURL&lt;/code&gt; with your endpoint within &lt;code&gt;mounted()&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;baseURL: 'https://YOUR_END_POINT.amazonaws.com/dev',

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

&lt;/div&gt;



&lt;p&gt;Finally, build your app and deploy it to CloudFront.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
npm run deploy

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

&lt;/div&gt;



&lt;p&gt;Navigate to your CloudFront URL, and you should have a working app! Congratulations on a job well done!&lt;/p&gt;

&lt;p&gt;If your CloudFront URL failed to pull the latest version of your web app, you might need to invalidate the CDN cache. Go to your distribution, click on the &lt;strong&gt;Invalidations&lt;/strong&gt; tab. Click &lt;strong&gt;Create Invalidation&lt;/strong&gt; and invalidate paths “/*”. It will take a few minutes, but once it’s complete, you should be able to pull in the latest version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Amazon Web Services is a robust platform that can pretty much do anything. But, it has a relatively steep learning curve and might not be right for all cloud beginners. Nonetheless, I encourage you to dig more into what AWS provides and find the right balance for your development needs.&lt;/p&gt;

&lt;p&gt;You can find the full source code for this tutorial at: &lt;a href="https://github.com/oktadeveloper/okta-secure-vue-aws-client-example" rel="noopener noreferrer"&gt;https://github.com/oktadeveloper/okta-secure-vue-aws-client-example&lt;/a&gt; and &lt;a href="https://github.com/oktadeveloper/okta-secure-vue-aws-server-example" rel="noopener noreferrer"&gt;https://github.com/oktadeveloper/okta-secure-vue-aws-server-example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are a few other articles I’d recommend to learn more about user authentication with common SPA frameworks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2018/02/15/build-crud-app-vuejs-node"&gt;Build a Basic CRUD App with Vue.js and Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2018/06/05/authentication-vanilla-js"&gt;Add Authentication to Your Vanilla JavaScript App in 20 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2017/03/30/react-okta-sign-in-widget"&gt;Build a React Application with User Authentication in 15 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2017/03/27/angular-okta-sign-in-widget"&gt;Build an Angular App with Okta’s Sign-in Widget in 15 Minutes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please be sure to &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;follow @oktadev on Twitter&lt;/a&gt; to get notified when more articles like this are published.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>javascript</category>
      <category>security</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Build a Basic CRUD App with Vue.js and Node</title>
      <dc:creator>Brandon Parise</dc:creator>
      <pubDate>Wed, 06 Jun 2018 21:28:29 +0000</pubDate>
      <link>https://dev.to/oktadev/build-a-basic-crud-app-with-vuejs-and-node-4cl8</link>
      <guid>https://dev.to/oktadev/build-a-basic-crud-app-with-vuejs-and-node-4cl8</guid>
      <description>&lt;p&gt;I've danced the JavaScript framework shuffle for years starting with jQuery, then on to Angular. After being frustrated with Angular's complexity, I found React and thought I was in the clear. What seemed simple on the surface ended up being a frustrating mess. Then I found Vue.js.  It just felt right. It worked as expected. It was fast. The documentation was incredible. Templating was eloquent. There was a unanimous consensus around how to handle state management, conditional rendering, two-way binding, routing, and more.&lt;/p&gt;

&lt;p&gt;This tutorial will take you step by step through scaffolding a Vue.js project, offloading secure authentication to &lt;a href="https://dev.to/docs/api/resources/oidc"&gt;Okta's OpenID Connect API (OIDC)&lt;/a&gt;, locking down protected routes, and performing CRUD operations through a backend REST API server. This tutorial uses the following technologies but doesn't require intimate knowledge to follow along:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vue.js with &lt;a href="https://github.com/vuejs/vue-cli" rel="noopener noreferrer"&gt;vue-cli&lt;/a&gt;, &lt;a href="https://github.com/vuejs/vue-router" rel="noopener noreferrer"&gt;vue-router&lt;/a&gt;, and &lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/okta-vue" rel="noopener noreferrer"&gt;Okta Vue SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Node with &lt;a href="https://github.com/expressjs/express" rel="noopener noreferrer"&gt;Express&lt;/a&gt;, &lt;a href="https://github.com/okta/okta-auth-js" rel="noopener noreferrer"&gt;Okta JWT Verifier&lt;/a&gt;, &lt;a href="https://github.com/sequelize/sequelize" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt;, and &lt;a href="https://github.com/dchester/epilogue" rel="noopener noreferrer"&gt;Epilogue&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Vue.js is a robust but simple Javascript framework. It has one of the lowest barriers to entry of any modern framework while providing all the required features for high performance web applications.&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%2Fvue-crud-node%2Fvue-homepage-8a8c67ceb95ba55306607a4cd4fd0a1d1a3821ab6f9facd7024e2ed1d806c714.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%2Fvue-crud-node%2Fvue-homepage-8a8c67ceb95ba55306607a4cd4fd0a1d1a3821ab6f9facd7024e2ed1d806c714.png" alt="Vue.js Homepage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial covers two primary builds, a frontend web app and backend REST API server. The frontend will be a single page application (SPA) with a homepage, login and logout, and a posts manager.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/docs/api/resources/oidc"&gt;Okta's OpenID Connect (OIDC)&lt;/a&gt; will handle our web app's authentication through the use of &lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/okta-vue" rel="noopener noreferrer"&gt;Okta's Vue SDK&lt;/a&gt;. If an unauthenticated user navigates to the posts manager, the web app should attempt to authenticate the user.&lt;/p&gt;

&lt;p&gt;The server will run &lt;a href="https://www.expressjs.com/" rel="noopener noreferrer"&gt;Express&lt;/a&gt; with &lt;a href="http://docs.sequelizejs.com/" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt; and &lt;a href="https://github.com/dchester/epilogue" rel="noopener noreferrer"&gt;Epilogue&lt;/a&gt;. At a high level, with Sequelize and Epilogue you can quickly generate dynamic REST endpoints with just a few lines of code.&lt;/p&gt;

&lt;p&gt;You will use JWT-based authentication when making requests from the web app and &lt;a href="https://github.com/okta/okta-oidc-js/tree/master/packages/jwt-verifier" rel="noopener noreferrer"&gt;Okta's JWT Verifier&lt;/a&gt; in an Express middleware to validate the token. Your app will expose the following endpoints which all require requests to have a valid access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- GET /posts
- GET /posts/:id
- POST /posts
- PUT /posts/:id
- DELETE /posts/:id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;To get your project off the ground quickly you can leverage the scaffolding functionality from &lt;a href="https://github.com/vuejs/vue-cli" rel="noopener noreferrer"&gt;vue-cli&lt;/a&gt;. For this tutorial, you are going to use the &lt;a href="https://github.com/vuejs-templates/pwa" rel="noopener noreferrer"&gt;progressive web app (PWA) template&lt;/a&gt; that includes a handful of features including &lt;a href="https://github.com/webpack/webpack" rel="noopener noreferrer"&gt;webpack&lt;/a&gt;, &lt;a href="https://vue-loader.vuejs.org/guide/hot-reload.html" rel="noopener noreferrer"&gt;hot reloading&lt;/a&gt;, CSS extraction, and unit testing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're not familiar with the tenets of PWA, check out our &lt;a href="https://dev.to/blog/2017/07/20/the-ultimate-guide-to-progressive-web-applications"&gt;ultimate guide to progressive web applications&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To install &lt;code&gt;vue-cli&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 vue-cli@2.9.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to initialize your project.  When you run the &lt;code&gt;vue init&lt;/code&gt; command just accept all the default values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vue init pwa my-vue-app
cd ./my-vue-app
npm install
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point your favorite browser to &lt;code&gt;http://localhost:8080&lt;/code&gt; and you should see the fruits of your labor:&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%2Fvue-crud-node%2Fwelcome-to-vue-pwa-eea589caa41609323c8793291ebd75f19e9e9139b9165a077005118577def59e.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%2Fvue-crud-node%2Fwelcome-to-vue-pwa-eea589caa41609323c8793291ebd75f19e9e9139b9165a077005118577def59e.png" alt="Welcome to Your Vue.js PWA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Extra Credit&lt;/strong&gt;: Check out the other &lt;a href="https://github.com/vuejs-templates" rel="noopener noreferrer"&gt;templates&lt;/a&gt; available for &lt;code&gt;vue-cli&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Bootstrap
&lt;/h2&gt;

&lt;p&gt;Let's install &lt;a href="https://github.com/bootstrap-vue/bootstrap-vue" rel="noopener noreferrer"&gt;bootstrap-vue&lt;/a&gt; so you can take advantage of the various premade &lt;a href="https://getbootstrap.com/docs/4.0/components/" rel="noopener noreferrer"&gt;components&lt;/a&gt; (plus you can keep the focus on functionality and not on custom CSS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i bootstrap-vue@2.0.0-rc.7 bootstrap@4.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To complete the installation, modify &lt;code&gt;./src/main.js&lt;/code&gt; to include &lt;a href="https://github.com/bootstrap-vue/bootstrap-vue" rel="noopener noreferrer"&gt;bootstrap-vue&lt;/a&gt; and import the required CSS files. Your &lt;code&gt;./src/main.js&lt;/code&gt; file should look 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="c1"&gt;// The Vue build version to load with the `import` command&lt;/span&gt;
&lt;span class="c1"&gt;// (runtime-only or standalone) has been set in webpack.base.conf with an alias.&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;BootstrapVue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap/dist/css/bootstrap.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bootstrap-vue/dist/bootstrap-vue.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;Vue&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;BootstrapVue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productionTip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="cm"&gt;/* eslint-disable no-new */&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;App/&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;components&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add Authentication with Okta
&lt;/h2&gt;

&lt;p&gt;Dealing with authentication in a web app is the bane of every developer's existence. That's where Okta comes in to secure your web applications with minimal code. To get started, you will need to create an OIDC 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%2Fvue-crud-node%2Fokta-developer-sign-up-8076b22d5d523a70c1c8a0cef34993103f3a2d01d821d2cc31a1f3ba9798cb08.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%2Fvue-crud-node%2Fokta-developer-sign-up-8076b22d5d523a70c1c8a0cef34993103f3a2d01d821d2cc31a1f3ba9798cb08.png" alt="Okta Developer Sign Up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once logged in, create a new application by clicking "Add 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%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fvue-crud-node%2Fadd-application-024fdfa427033e2e345b48167d8fdef2592f8dcaa464be89487e257a629d39ad.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%2Fvue-crud-node%2Fadd-application-024fdfa427033e2e345b48167d8fdef2592f8dcaa464be89487e257a629d39ad.png" alt="Add Application"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the "Single-Page App" platform option.&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%2Fvue-crud-node%2Fnew-application-options-96b1b0faa43717d47faaf99696fe2155e793c5f482b7cbae21747bdf3fd72ba4.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%2Fvue-crud-node%2Fnew-application-options-96b1b0faa43717d47faaf99696fe2155e793c5f482b7cbae21747bdf3fd72ba4.png" alt="New Application Options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The default application settings should be the same as those pictured.&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%2Fvue-crud-node%2Fokta-application-settings-99892ff83b5e572a4c2b64d3d9b2edde2266d7f7434c18b8e60f6f005d7718e0.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%2Fvue-crud-node%2Fokta-application-settings-99892ff83b5e572a4c2b64d3d9b2edde2266d7f7434c18b8e60f6f005d7718e0.png" alt="Okta Application Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install the Okta Vue SDK, run 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;npm i @okta/okta-vue@1.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;./src/router/index.js&lt;/code&gt; and replace the entire file with the following code.&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PostsManager&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/PostsManager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@okta/okta-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;Vue&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;Auth&lt;/span&gt;&lt;span class="p"&gt;,&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://{yourOktaDomain}.com/oauth2/default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{yourClientId}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8080/implicit/callback&lt;/span&gt;&lt;span class="dl"&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="s1"&gt;openid profile email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nx"&gt;Vue&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;Router&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;router&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;Router&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;history&lt;/span&gt;&lt;span class="dl"&gt;'&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="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Hello&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/implicit/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleCallback&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts-manager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PostsManager&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PostsManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;requiresAuth&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="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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authRedirectGuard&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You'll need to replace &lt;code&gt;{yourOktaDomain}&lt;/code&gt; and &lt;code&gt;{yourClientId}&lt;/code&gt; which can be found on your application overview page in the Okta Developer Console. This will inject an &lt;code&gt;authClient&lt;/code&gt; object into your Vue instance which can be accessed by calling &lt;code&gt;this.$auth&lt;/code&gt; anywhere inside your Vue instance.&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;Vue&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;Auth&lt;/span&gt;&lt;span class="p"&gt;,&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://{yourOktaDomain}.com/oauth2/default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{yourClientId}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8080/implicit/callback&lt;/span&gt;&lt;span class="dl"&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="s1"&gt;openid profile email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final step of Okta's authentication flow is redirecting the user back to your app with the token values in the URL. The &lt;code&gt;Auth.handleCallback()&lt;/code&gt; component included in the SDK handles the redirect and persists the tokens on the browser.&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/implicit/callback&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleCallback&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;You also need to lock down protected routes from being access by unauthenticated users. This is accomplished by implementing a &lt;a href="https://router.vuejs.org/en/advanced/navigation-guards" rel="noopener noreferrer"&gt;navigation guard&lt;/a&gt;. As the name suggests, &lt;a href="https://router.vuejs.org/en/advanced/navigation-guards" rel="noopener noreferrer"&gt;navigation guards&lt;/a&gt; are primarily used to guard navigations either by redirecting or canceling.&lt;/p&gt;

&lt;p&gt;The SDK comes with the method &lt;code&gt;auth.authRedirectGuard()&lt;/code&gt; that checks matched routes' metadata for the key &lt;code&gt;requiresAuth&lt;/code&gt; and redirects the user to the authentication flow if they are not authenticated.&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;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authRedirectGuard&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this navigation guard installed, any route that has the following metadata will be protected.&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;meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;requiresAuth&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customize Your App Layout in Vue
&lt;/h2&gt;

&lt;p&gt;The web app's layout is located in a component &lt;code&gt;./src/App.vue&lt;/code&gt;.  You can use the &lt;a href="https://router.vuejs.org/en/api/router-view" rel="noopener noreferrer"&gt;router-view&lt;/a&gt; component to render the matched component for the given path.&lt;/p&gt;

&lt;p&gt;For the main menu, you'll want to change the visibility of certain menu items based on the status of the &lt;code&gt;activeUser&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not Authenticated: Show only &lt;em&gt;Login&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;Authenticated: Show only &lt;em&gt;Logout&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can toggle the visibility of these menu items using the &lt;code&gt;v-if&lt;/code&gt; directive in Vue.js that checks the existence of &lt;code&gt;activeUser&lt;/code&gt; on the component.  When the component is loaded (which calls &lt;code&gt;created()&lt;/code&gt;) or when a route changes we want to refresh the &lt;code&gt;activeUser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;./src/App.vue&lt;/code&gt; and copy/paste the following code.&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;b-navbar&lt;/span&gt; &lt;span class="na"&gt;toggleable=&lt;/span&gt;&lt;span class="s"&gt;"md"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt; &lt;span class="na"&gt;variant=&lt;/span&gt;&lt;span class="s"&gt;"dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;b-navbar-toggle&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"nav_collapse"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/b-navbar-toggle&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;b-navbar-brand&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;My Vue App&lt;span class="nt"&gt;&amp;lt;/b-navbar-brand&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;b-collapse&lt;/span&gt; &lt;span class="na"&gt;is-nav&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"nav_collapse"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;b-navbar-nav&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;b-nav-item&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/b-nav-item&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;b-nav-item&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"/posts-manager"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Posts Manager&lt;span class="nt"&gt;&amp;lt;/b-nav-item&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;b-nav-item&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click.prevent=&lt;/span&gt;&lt;span class="s"&gt;"login"&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"!activeUser"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Login&lt;span class="nt"&gt;&amp;lt;/b-nav-item&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;b-nav-item&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click.prevent=&lt;/span&gt;&lt;span class="s"&gt;"logout"&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Logout&lt;span class="nt"&gt;&amp;lt;/b-nav-item&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/b-navbar-nav&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/b-collapse&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/b-navbar&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- routes will be rendered here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;router-view&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;data &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;activeUser&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="p"&gt;},&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;created &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshActiveUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// everytime a route is changed refresh the activeUser&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;refreshActiveUser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;login &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loginRedirect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;refreshActiveUser &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;logout &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshActiveUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;this&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;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every login must have a logout. The following snippet will logout your user, refresh the active user (which is now null), and then redirect the user to the homepage. This method is called when a user clicks on the logout link in the nav.&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;logout &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&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="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshActiveUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;this&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;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://vuejs.org/v2/guide/components" rel="noopener noreferrer"&gt;Components&lt;/a&gt; are the building blocks within Vue.js.  Each of your pages will be defined in the app as a component. Since the vue-cli webpack template utilizes &lt;a href="https://github.com/vuejs/vue-loader" rel="noopener noreferrer"&gt;vue-loader&lt;/a&gt;, your component source files have a convention that separates template, script, and style (&lt;a href="https://github.com/vuejs/vue-loader" rel="noopener noreferrer"&gt;see here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Now that you've added vue-bootstrap, modify &lt;code&gt;./src/components/Hello.vue&lt;/code&gt; to remove the boilerplate links vue-cli generates.&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hero"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"display-3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"lead"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;This is the homepage of your vue app&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nc"&gt;.hero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nc"&gt;.hero&lt;/span&gt; &lt;span class="nc"&gt;.lead&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point you can stub out the Post Manager page to test your authentication flow. Once you confirm authentication works, you'll start to build out the API calls and components required to perform CRUD operations on your Posts model. &lt;/p&gt;

&lt;p&gt;Create a new file &lt;code&gt;./src/components/PostsManager.vue&lt;/code&gt; and paste the following code:&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container-fluid mt-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Posts Manager&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Only authenticated users should see this page&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Take Your Vue.js Frontend and Auth Flows for a Test Drive
&lt;/h2&gt;

&lt;p&gt;In your terminal run &lt;code&gt;npm run dev&lt;/code&gt; (if it's not already running). Navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt; and you should see the new homepage.&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%2Fvue-crud-node%2Fnew-homepage-7bbf1b612f5d02bff93d2a233345bfa0d621a5b1ec1cde5d8a40dd8b7998ff50.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%2Fvue-crud-node%2Fnew-homepage-7bbf1b612f5d02bff93d2a233345bfa0d621a5b1ec1cde5d8a40dd8b7998ff50.png" alt="Hello World"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you click &lt;strong&gt;Posts Manager&lt;/strong&gt; or &lt;strong&gt;Login&lt;/strong&gt; you should be directed to Okta's flow.  Enter your Okta dev account credentials.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; If you are logged in to your Okta Developer Account you will be redirected automatically back to the app. You can test this by using incognito or private browsing mode.&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%2Fvue-crud-node%2Fokta-sign-in-84e74fdcd14ea14cfef67942450ef280e251773e6621e8c4d8fbeb585f5ab068.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%2Fvue-crud-node%2Fokta-sign-in-84e74fdcd14ea14cfef67942450ef280e251773e6621e8c4d8fbeb585f5ab068.png" alt="Okta Sign-In"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If successful, you should return to the homepage logged in.&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%2Fvue-crud-node%2Fhomepage-authenticated-12cf39e1a94d81657ebf0ba6d02b42c61f59d81ed911b13a00968742397ff7d5.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%2Fvue-crud-node%2Fhomepage-authenticated-12cf39e1a94d81657ebf0ba6d02b42c61f59d81ed911b13a00968742397ff7d5.png" alt="Homepage after logging in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on &lt;strong&gt;Posts Manager&lt;/strong&gt; link should render the protected component.&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%2Fvue-crud-node%2Fposts-manager-e371e794a03cd91955e0bc4661a5f6a0649f4532ebde18531fb23997dd174849.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%2Fvue-crud-node%2Fposts-manager-e371e794a03cd91955e0bc4661a5f6a0649f4532ebde18531fb23997dd174849.png" alt="Posts Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a Backend REST API Server
&lt;/h2&gt;

&lt;p&gt;Now that users can securely authenticate, you can build the REST API server to perform CRUD operations on a post model. Add the following dependencies to 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;npm i express@4.16.3 cors@2.8.4 @okta/jwt-verifier@0.0.11 sequelize@4.37.6 sqlite3@4.0.0 epilogue@0.7.1 axios@0.18.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create the file  &lt;code&gt;./src/server.js&lt;/code&gt; and paste the following code.&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="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="s1"&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;cors&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="s1"&gt;cors&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="s1"&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;Sequelize&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="s1"&gt;sequelize&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;epilogue&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="s1"&gt;epilogue&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;OktaJwtVerifier&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="s1"&gt;@okta/jwt-verifier&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;oktaJwtVerifier&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;OktaJwtVerifier&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{yourClientId}&lt;/span&gt;&lt;span class="dl"&gt;'&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://{yourOktaDomain}.com/oauth2/default&lt;/span&gt;&lt;span class="dl"&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;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;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;cors&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;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;// verify JWT token 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="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="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// require every request to have an authorization header&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&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;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization header is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&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;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&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;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;oktaJwtVerifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verifyAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jwt&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="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// jwt did not verify!&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// For ease of this tutorial, we are going to use SQLite to limit dependencies&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;database&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;Sequelize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./test.sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Define our Post model&lt;/span&gt;
&lt;span class="c1"&gt;// id, createdAt, and updatedAt are added by sequelize automatically&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posts&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;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEXT&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Initialize epilogue&lt;/span&gt;
&lt;span class="nx"&gt;epilogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;app&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="na"&gt;sequelize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Create the dynamic REST resource for our Post model&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;epilogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/:id&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;// Resets the database and launches the express app on :8081&lt;/span&gt;
&lt;span class="nx"&gt;database&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;force&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="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="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="mi"&gt;8081&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;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="s1"&gt;listening to port localhost:8081&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to replace the variables &lt;code&gt;{yourOktaDomain}&lt;/code&gt; and &lt;code&gt;{clientId}&lt;/code&gt; in the above code with values from your OIDC app in Okta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Sequelize
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/sequelize/sequelize" rel="noopener noreferrer"&gt;Sequelize&lt;/a&gt; is a promise-based ORM for Node.js. It supports the dialects PostgreSQL, MySQL, SQLite, and MSSQL and features solid transaction support, relations, read replication, and more.&lt;/p&gt;

&lt;p&gt;For ease of this tutorial, you're going to use SQLite to limit external dependencies. The following code initializes a Sequelize instance using SQLite as your driver.&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;database&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;Sequelize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./test.sqlite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each post has a &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt;. (The fields &lt;code&gt;createdAt&lt;/code&gt;, and &lt;code&gt;updatedAt&lt;/code&gt; are added by Sequelize automatically). With Sequelize, you define models by calling &lt;code&gt;define()&lt;/code&gt; on your instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let Post = database.define('posts', {
  title: Sequelize.STRING,
  body: Sequelize.TEXT
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add Epilogue
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dchester/epilogue" rel="noopener noreferrer"&gt;Epilogue&lt;/a&gt; creates flexible REST endpoints from Sequelize models within an Express app. If you ever coded REST endpoints you know how much repetition there is. D.R.Y. FTW!&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;// Initialize epilogue&lt;/span&gt;
&lt;span class="nx"&gt;epilogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;app&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="na"&gt;sequelize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Create the dynamic REST resource for our Post model&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;userResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;epilogue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts/:id&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;h3&gt;
  
  
  Verify Your JWT
&lt;/h3&gt;

&lt;p&gt;This is the most crucial component of your REST API server. Without this middleware any user can perform CRUD operations on our database. If no authorization header is present, or the access token is invalid, the API call will fail and return an error.&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;// verify JWT token 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="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="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// require every request to have an authorization header&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&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;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Authorization header is required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&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;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&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;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;oktaJwtVerifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verifyAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jwt&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="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sub&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// jwt did not verify!&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the Server
&lt;/h3&gt;

&lt;p&gt;Open a new terminal window and run the server with the command &lt;code&gt;node ./src/server&lt;/code&gt;.  You should see debug information from Sequelize and the app listening on port 8081.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete the Posts Manager Component
&lt;/h2&gt;

&lt;p&gt;Now that the REST API server is complete, you can start wiring up your posts manager to fetch posts, create posts, edit posts, and delete posts. &lt;/p&gt;

&lt;p&gt;I always centralize my API integrations into a single helper module. This keeps the code in components much cleaner and provides single location in case you need to change anything with the API request.&lt;/p&gt;

&lt;p&gt;Create a file &lt;code&gt;./src/api.js&lt;/code&gt; and copy/paste the following code into 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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;axios&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;baseURL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8081/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;execute &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// inject the accessToken for each request&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&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;client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&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;return&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;data&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;getPosts &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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&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="nf"&gt;getPost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;createPost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;updatePost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;put&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;deletePost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you authenticate with OIDC, an access token is persisted locally in the browser.  Since each API request must have an access token, you can fetch it from the authentication client and set it in the request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;$auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAccessToken&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;client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By creating the following proxy methods inside your API helper, the code outside the helper module remains clean and semantic.&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="nf"&gt;getPosts &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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&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="nf"&gt;getPost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="nf"&gt;createPost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="nf"&gt;updatePost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;put&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="nf"&gt;deletePost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delete&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`/posts/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have all the components required to wire up your posts manager component to make CRUD operations via the REST API. Open &lt;code&gt;./src/components/PostsManager.vue&lt;/code&gt; and copy/paste the following code.&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;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container-fluid mt-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"h1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Posts Manager&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;b-alert&lt;/span&gt; &lt;span class="na"&gt;:show=&lt;/span&gt;&lt;span class="s"&gt;"loading"&lt;/span&gt; &lt;span class="na"&gt;variant=&lt;/span&gt;&lt;span class="s"&gt;"info"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/b-alert&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;b-row&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;b-col&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"table table-striped"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;ID&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Updated At&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;&lt;span class="ni"&gt;&amp;amp;nbsp;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;tr&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"post in posts"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"post.id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ post.id }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ post.title }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;{{ post.updatedAt }}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-right"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click.prevent=&lt;/span&gt;&lt;span class="s"&gt;"populatePostToEdit(post)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Edit&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; - 
                &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click.prevent=&lt;/span&gt;&lt;span class="s"&gt;"deletePost(post.id)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Delete&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/b-col&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;b-col&lt;/span&gt; &lt;span class="na"&gt;lg=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;b-card&lt;/span&gt; &lt;span class="na"&gt;:title=&lt;/span&gt;&lt;span class="s"&gt;"(model.id ? 'Edit Post ID#' + model.id : 'New Post')"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;submit.prevent=&lt;/span&gt;&lt;span class="s"&gt;"savePost"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;b-form-group&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;b-form-input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"model.title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/b-form-input&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/b-form-group&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;b-form-group&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;b-form-textarea&lt;/span&gt; &lt;span class="na"&gt;rows=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"model.body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/b-form-textarea&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/b-form-group&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;b-btn&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;variant=&lt;/span&gt;&lt;span class="s"&gt;"success"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save Post&lt;span class="nt"&gt;&amp;lt;/b-btn&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/b-card&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/b-col&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/b-row&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;data &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;loading&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="na"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="na"&gt;model&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;created &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;refreshPosts &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;populatePostToEdit &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;savePost &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updatePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;// reset form&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshPosts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;deletePost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Are you sure you want to delete this post?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// if we are editing a post we deleted, remove it from the form&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deletePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshPosts&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Listing Posts
&lt;/h3&gt;

&lt;p&gt;You'll use&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 to fetch posts from your REST API server. You should refresh the list of posts when the component is loaded and after any mutating operation (create, update, or delete).



```javascript
async refreshPosts () {
  this.loading = true
  this.posts = await api.getPosts()
  this.loading = false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The attribute &lt;code&gt;this.loading&lt;/code&gt; is toggled so the UI can reflect the pending API call. You might not see the loading message since the API request is not going out to the internet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Posts
&lt;/h3&gt;

&lt;p&gt;A form is included in the component to save a post. It's wired up to call &lt;code&gt;savePosts()&lt;/code&gt; when the form is submitted and its inputs are bound to the &lt;code&gt;model&lt;/code&gt; object on the component.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;savePost()&lt;/code&gt; is called, it will perform either an update or create based on the existence of &lt;code&gt;model.id&lt;/code&gt;. This is mostly a shortcut to not have to define two separate forms for creating and updating.&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;savePost &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updatePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;// reset form&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshPosts&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;h3&gt;
  
  
  Updating Posts
&lt;/h3&gt;

&lt;p&gt;When updating a post, you first must load the post into the form. This sets &lt;code&gt;model.id&lt;/code&gt; which will the trigger an update in &lt;code&gt;savePost()&lt;/code&gt;.&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;populatePostToEdit &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({},&lt;/span&gt; &lt;span class="nx"&gt;post&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;&lt;strong&gt;Important:&lt;/strong&gt; The &lt;code&gt;Object.assign()&lt;/code&gt; call copies the value of the post argument rather than the reference. When dealing with mutation of objects in Vue, you should always set to the value, not reference.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting Posts
&lt;/h3&gt;

&lt;p&gt;To delete a post simply call &lt;code&gt;api.deletePost(id)&lt;/code&gt;. It's always good to confirm before delete so let's throw in a native confirmation alert box to make sure the click was intentional.&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;deletePost &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Are you sure you want to delete this post?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deletePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;refreshPosts&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;h2&gt;
  
  
  Test Your Vue.js + Node CRUD App
&lt;/h2&gt;

&lt;p&gt;Make sure both the server and frontend are running.&lt;/p&gt;

&lt;p&gt;Terminal #1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node ./src/server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terminal #2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt; and give it a whirl.&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%2Fvue-crud-node%2Fnew-post-464637114d9c541ea48aa4dcc9fb698d6d5bf99cd2a3e5b39d81ffca6f7c406d.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%2Fvue-crud-node%2Fnew-post-464637114d9c541ea48aa4dcc9fb698d6d5bf99cd2a3e5b39d81ffca6f7c406d.png" alt="New Post"&gt;&lt;/a&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%2Fvue-crud-node%2Fnew-post-hello-world-357d85f922ecea2f414b35dbb90c310279e388d20da655c196fda04328c4a223.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%2Fvue-crud-node%2Fnew-post-hello-world-357d85f922ecea2f414b35dbb90c310279e388d20da655c196fda04328c4a223.png" alt="New Hello World Post"&gt;&lt;/a&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%2Fvue-crud-node%2Fdelete-post-3e5ec6eb05128b65782c45bfcf7dd1129579a57175141d9fb1cfcc776cd2efad.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%2Fvue-crud-node%2Fdelete-post-3e5ec6eb05128b65782c45bfcf7dd1129579a57175141d9fb1cfcc776cd2efad.png" alt="Delete Post"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Do More With Vue!
&lt;/h2&gt;

&lt;p&gt;As I said at the top of this post, I think Vue stands head and shoulders above other frameworks. Here are five quick reasons why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://vuejs.org/v2/guide/instance#Lifecycle-Diagram" rel="noopener noreferrer"&gt;Simple component lifecycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vuejs.org/v2/guide/syntax" rel="noopener noreferrer"&gt;HTML-based templating&lt;/a&gt; and native &lt;a href="https://vuejs.org/v2/guide/forms" rel="noopener noreferrer"&gt;two-way binding&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Widely agreed upon ways to handle &lt;a href="https://github.com/vuejs/vue-router" rel="noopener noreferrer"&gt;routing&lt;/a&gt;, &lt;a href="https://github.com/vuejs/vuex" rel="noopener noreferrer"&gt;state management&lt;/a&gt;, &lt;a href="https://github.com/vuejs/vue-loader" rel="noopener noreferrer"&gt;webpack configuration&lt;/a&gt;, and &lt;a href="https://nuxtjs.org/" rel="noopener noreferrer"&gt;isomorphic web apps&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Massive community supported &lt;a href="https://github.com/vuejs/awesome-vue" rel="noopener noreferrer"&gt;resources, components, libraries, and projects&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Vue feels very similar to &lt;a href="https://github.com/facebook/react" rel="noopener noreferrer"&gt;React&lt;/a&gt; (without the JSX!) which lowers the barrier to entry for those with React experience. Moving between React and Vue isn't very difficult.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I covered a lot of material in this tutorial but don't feel bad if you didn't grasp everything the first time. The more you work with these technologies, the more familiar they will become.&lt;/p&gt;

&lt;p&gt;To learn more about Vue.js head over to &lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;https://vuejs.org&lt;/a&gt; or check out these other great resources from the &lt;a href="https://twitter.com/OktaDev" rel="noopener noreferrer"&gt;@oktadev team&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2017/07/20/the-ultimate-guide-to-progressive-web-applications"&gt;The Ultimate Guide to Progressive Web Applications&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2017/09/14/lazy-developers-guide-to-auth-with-vue"&gt;The Lazy Developer's Guide to Authentication with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/2017/09/06/build-a-cryptocurrency-comparison-site-with-vuejs"&gt;Build a Cryptocurrency Comparison Site with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the source code for the application developed in this post at &lt;a href="https://github.com/oktadeveloper/okta-vue-node-example" rel="noopener noreferrer"&gt;https://github.com/oktadeveloper/okta-vue-node-example&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Hit me up in the comments with any questions, and as always, follow &lt;a href="https://twitter.com/OktaDev" rel="noopener noreferrer"&gt;@oktadev&lt;/a&gt; on Twitter to see all the cool content our dev team is creating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apr 16, 2018: Updated to use the latest dependencies, including Okta's Vue SDK 1.0.0. See the code changes in &lt;a href="https://github.com/oktadeveloper/okta-vue-node-example/pull/2" rel="noopener noreferrer"&gt;oktadeveloper/okta-vue-node-example-example#2&lt;/a&gt;. Changes to this article can be viewed in &lt;a href="https://github.com/okta/okta.github.io/pull/1959" rel="noopener noreferrer"&gt;okta/okta.github.io#1959&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Mar 12, 2018: Updated to use the latest dependencies, including Bootstrap 4.0.0. See the code changes in &lt;a href="https://github.com/oktadeveloper/okta-vue-node-example/pull/1" rel="noopener noreferrer"&gt;oktadeveloper/okta-vue-node-example-example#1&lt;/a&gt;. Changes to this article can be viewed in &lt;a href="https://github.com/okta/okta.github.io/pull/1837" rel="noopener noreferrer"&gt;okta/okta.github.io#1837&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>webdev</category>
      <category>node</category>
    </item>
  </channel>
</rss>
