<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lee Brandt</title>
    <description>The latest articles on Forem by Lee Brandt (@leebrandt).</description>
    <link>https://forem.com/leebrandt</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%2F54764%2Fe339f474-707b-4cc7-89cd-baef76500066.jpeg</url>
      <title>Forem: Lee Brandt</title>
      <link>https://forem.com/leebrandt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/leebrandt"/>
    <language>en</language>
    <item>
      <title>A Quick Guide to Integrating React and GraphQL</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Wed, 04 Dec 2019 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/a-quick-guide-to-integrating-react-and-graphql-11aj</link>
      <guid>https://forem.com/oktadev/a-quick-guide-to-integrating-react-and-graphql-11aj</guid>
      <description>&lt;p&gt;If your application consumes a ReST API from React, the default setup will give you ALL the data for a resource. But if you want to specify what data you need, GraphQL can help! Specifying exactly the data you want can reduce the amount of data sent over the wire, and the React applications you write can have less code filtering out useless data from data you need.&lt;/p&gt;

&lt;p&gt;There are a lot of GraphQL clients to choose from. Two of the most popular are Apollo and Relay, but both are powerful and might be too complex for a beginner. Luckily, each offers a preconfigured “light” option: Apollo Boost and Relay Modern.&lt;/p&gt;

&lt;p&gt;For this article, you will use Apollo Boost to do GraphQL queries and mutations from a React frontend to a .NET Core backend. Emphasis here is on the frontend and the GraphQL setup, so you will start by simply cloning a functional backend &lt;a href="https://github.com/oktadeveloper/okta-dotnet-react-graphql-example"&gt;from Github&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/oktadeveloper/okta-dotnet-react-graphql-example.git

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

&lt;/div&gt;



&lt;p&gt;This backend uses EntityFramework Core and that powers an in-memory database with books and authors so you can keep a reading list. It is based on another Okta blog post, &lt;a href="https://developer.okta.com/blog/2019/04/16/graphql-api-with-aspnetcore"&gt;Build a GraphQL API with ASP.NET Core&lt;/a&gt;, so follow that post to understand more of what happens in the backend. One caveat: that backend is made with &lt;code&gt;dotnet new webapi&lt;/code&gt;, while the close we use in this post is made with &lt;code&gt;dotnet new react&lt;/code&gt;. This adds a starter React frontend application, and it also sets up hot reloading, which works straight out of the box when running it in Visual Studio or with the &lt;code&gt;dotnet&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Apollo Boost to the React Frontend
&lt;/h2&gt;

&lt;p&gt;Open a terminal and go to the folder &lt;code&gt;ClientApp&lt;/code&gt;, which contains the React frontend. Run these npm-commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;apollo-boost @apollo/react-hooks graphql

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

&lt;/div&gt;



&lt;p&gt;The first one downloads all packages already referenced, and then the second adds Apollo Boost, a library that supports using React Hooks to access GraphQL, and the main GraphQL itself.&lt;/p&gt;

&lt;p&gt;React Hooks was released with React v16.8 early in 2019, and it enables using state and other features in React in simple function components. So, you don’t need to write a class!&lt;/p&gt;

&lt;p&gt;Open &lt;strong&gt;Layout.js&lt;/strong&gt;, which sets the main layout for the application, and update it to 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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;}&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;reactstrap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NavMenu&lt;/span&gt; &lt;span class="p"&gt;}&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;./NavMenu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="p"&gt;}&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;@apollo/react-hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ApolloClient&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;apollo-boost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Layout&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;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;/graphql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientParam&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NavMenu&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Container&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ApolloProvider&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ApolloProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Container&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The tag &lt;code&gt;&amp;lt;ApolloProvider client={client}&amp;gt;&lt;/code&gt; must surround all components that will use GraphQL queries. It also must be configured with an &lt;code&gt;ApolloClient&lt;/code&gt; instantiated with a parameter telling the URL of the GraphQL endpoint in the backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rewrite React Component to Use GraphQL
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;components&lt;/code&gt; folder, open the &lt;code&gt;FetchData&lt;/code&gt; component and clear everything in it. You will use &lt;code&gt;FetchData&lt;/code&gt; to do a simple query and mutation. Start by adding these imports at the top of the file:&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;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt; &lt;span class="p"&gt;}&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useMutation&lt;/span&gt; &lt;span class="p"&gt;}&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;@apollo/react-hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="p"&gt;}&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;apollo-boost&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 first line imports &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useCallback&lt;/code&gt;, which are hooks that save state and implement event handlers. The second line imports &lt;code&gt;useQuery&lt;/code&gt; and &lt;code&gt;useMutation&lt;/code&gt;, which execute GraphQL queries and mutations. The last line imports &lt;code&gt;gql&lt;/code&gt;, which converts plain text to GraphQL queries and mutations. Use it straight away to define your first query. Add these lines right below the &lt;code&gt;import&lt;/code&gt; statements:&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;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`{
author(id:1){
    name,
    books {
      name
    }
  }
}`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is a GraphQL query for the author with an id of 1, and it asks for the name of the author, and a list of books with only the name of each book. Also, add this 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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runningQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&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;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;runningQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;runningQuery&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="nx"&gt;author&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;runningQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;GraphQL&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;pre&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;runningQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/pre&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt; &lt;/span&gt;&lt;span class="err"&gt;:
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&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;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&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;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;useQuery&lt;/code&gt; registers the query, using a hook. Once registered, the query starts the first time the component renders. When the query has finished, the component re-renders, and &lt;code&gt;runningQuery&lt;/code&gt; will either have data in &lt;code&gt;runningQuery.data&lt;/code&gt; or an error in &lt;code&gt;runningQuery.error&lt;/code&gt;. So, if the query returns with a data field that exists and an author, the component will show the name of the author and a list of all the author’s books.&lt;/p&gt;

&lt;p&gt;Now, you are ready to run the first version of the app. Press &lt;code&gt;ctrl+F5&lt;/code&gt; in Visual Studio, or run &lt;code&gt;dotnet run&lt;/code&gt; in the main folder in the terminal. Select &lt;strong&gt;Fetch Data&lt;/strong&gt; in the menu to load data from the backend. It should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IB14--cr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/app-first-run-3e778678eb5fbbf4cf3e50dcd6358c46e7ad5ff10d2010576c8ab52de2a037c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IB14--cr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/app-first-run-3e778678eb5fbbf4cf3e50dcd6358c46e7ad5ff10d2010576c8ab52de2a037c9.png" alt="App First Run" width="800" height="246"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, add the ability to update the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a GraphQL Mutation to Your React Component
&lt;/h2&gt;

&lt;p&gt;Updates are called &lt;em&gt;mutations&lt;/em&gt; in GraphQL. Add the following code above the function &lt;code&gt;FetchData()&lt;/code&gt; in the &lt;code&gt;FetchData.js&lt;/code&gt; file:&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;mutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
mutation ($name: String!, $id: ID!) {
  addBookToAuthor(name: $name, id: $id) {
    id
    name
    books {
      name
    }
  }
}`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;addBookToAuthor()&lt;/code&gt; mutation adds a book (&lt;code&gt;name&lt;/code&gt;) to an author (&lt;code&gt;id&lt;/code&gt;). The expression has two variables, the&lt;code&gt;$name&lt;/code&gt; of the author with a GraphQL type of &lt;code&gt;String!&lt;/code&gt; and &lt;code&gt;$id&lt;/code&gt; of type &lt;code&gt;ID!&lt;/code&gt;. The values &lt;code&gt;$name&lt;/code&gt; and &lt;code&gt;$id&lt;/code&gt; will be passed to the mutation before it runs.&lt;/p&gt;

&lt;p&gt;The mutation takes name and id as parameters and returns an author name and id inside the curly braces. Next, the mutation returns the id, name, and complete list of books for the author who was returned.&lt;/p&gt;

&lt;p&gt;To actually run the mutation, update the function &lt;code&gt;FetchData()&lt;/code&gt; to 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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FetchData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;myMutation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mutation&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;runningQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isSending&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsSending&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;newBookName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setNewBookName&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;authorFromMutation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setAuthorFromMutation&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newBookName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSending&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="nf"&gt;setIsSending&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;myMutation&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="p"&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="nx"&gt;newBookName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nf"&gt;setIsSending&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="nf"&gt;setAuthorFromMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="nx"&gt;addBookToAuthor&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;isSending&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;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authorFromMutation&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;runningQuery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;runningQuery&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="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&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;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&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;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="nx"&gt;Book&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;newBookName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setNewBookName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isSending&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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="nf"&gt;sendRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newBookName&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Add Book&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In the first line, &lt;code&gt;useMutation(mutation)&lt;/code&gt; registers the mutation in much the same way &lt;code&gt;useQuery(query)&lt;/code&gt; registers the query. These commands do not start the query or the mutation, they only set them up.&lt;/p&gt;

&lt;p&gt;Next, to avoid starting multiple mutations at the same time, you need to store mutation state that includes whether it is running and what the user is writing in the text input field for book. The mutation also returns data, which you will store in the state, in &lt;code&gt;authorFromMutation&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, the &lt;code&gt;sendRequest&lt;/code&gt; function runs the mutation, and is triggered by the user clicking the button. The first two lines ensure that only one mutation runs at a time.&lt;/p&gt;

&lt;p&gt;The code &lt;code&gt;myMutation({ variables: { name: newBookName, id: 1 } })&lt;/code&gt; executes the mutation with an author id of 1, and the book name entered by the user. The result is saved in the state with &lt;code&gt;setAuthorFromMutation()&lt;/code&gt;, and the next line selects &lt;code&gt;authorFromMutation&lt;/code&gt;, if it exists, and the result of the query if not.&lt;/p&gt;

&lt;p&gt;The HTML code is pretty much the same, but adds a text input field for new book names and a button to trigger the update.&lt;/p&gt;

&lt;p&gt;Now, run the application again and add a book. You can reload the page, and you should see that the new book is still there. Because the backend uses an in-memory database, the new books you add will be gone after you restart the backend. After you add a new book, the page should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S8rsXUVY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/app-final-run-23354652d2e48a2290cffdf513c5be33394f48a9feb58b1b0f1e8641c0746837.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S8rsXUVY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/app-final-run-23354652d2e48a2290cffdf513c5be33394f48a9feb58b1b0f1e8641c0746837.png" alt="App Final Run" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authentication to Your React GraphQL Application
&lt;/h2&gt;

&lt;p&gt;It is surprisingly easy to add authentication to both the backend and the frontend without writing it all yourself from scratch. You can integrate Okta to handle the authentication for you easily:&lt;/p&gt;

&lt;p&gt;Sign up for a &lt;a href="https://developer.okta.com/signup/"&gt;forever-free developer account&lt;/a&gt; (or login if you already have one). Once you have signed up and logged in, you’ll be taken to your dashboard. Make note of your Org URL in the top right corner. It looks something like this: &lt;code&gt;Org URL: https://dev-######.okta.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the backend project, edit the file &lt;code&gt;Startup.cs&lt;/code&gt; and replace &lt;code&gt;{yourOktaDomain}&lt;/code&gt; in the code below with the value from your Okta Developer Dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJwtBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authority&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/oauth2/default"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Audience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"api://default"&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 must also register your application in the Okta dashboard. Select &lt;strong&gt;Applications&lt;/strong&gt; at the top, and then click the green button, &lt;strong&gt;Add Application&lt;/strong&gt;. Select &lt;strong&gt;Single-Page App&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Enter “GraphQL” for &lt;strong&gt;Name&lt;/strong&gt;, and click &lt;strong&gt;Done&lt;/strong&gt;. Then click &lt;strong&gt;Edit&lt;/strong&gt; to go back to the form.&lt;/p&gt;

&lt;p&gt;Examine what port number your application uses in the browser, and in Okta change both &lt;strong&gt;Login redirect URIs&lt;/strong&gt; and the &lt;strong&gt;Initiate login URI&lt;/strong&gt; to use your port number &lt;em&gt;and&lt;/em&gt; to use &lt;code&gt;https&lt;/code&gt; instead of &lt;code&gt;http&lt;/code&gt;. Also, add a &lt;strong&gt;Logout redirect URIs&lt;/strong&gt; pointing to the root of your site. Make sure to check &lt;strong&gt;Authorization Code&lt;/strong&gt;. It should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tW_EvQOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/okta-app-settings-14e4b4960fc6490df992ef96bdf965ebc0af19b004630b62adb4019ac0d87776.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tW_EvQOF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/okta-app-settings-14e4b4960fc6490df992ef96bdf965ebc0af19b004630b62adb4019ac0d87776.png" alt="Okta App Settings" width="721" height="812"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The last thing you need to do in the dashboard is adding a trusted origin. Select &lt;strong&gt;API&lt;/strong&gt; in the top menu, and then &lt;strong&gt;Trusted Origins&lt;/strong&gt;. Click &lt;strong&gt;Add Origin&lt;/strong&gt;. Enter &lt;code&gt;Localhost&lt;/code&gt; for &lt;strong&gt;Name&lt;/strong&gt;, and the same base URL as your application for &lt;strong&gt;Origin URL&lt;/strong&gt;. Check both &lt;strong&gt;CORS&lt;/strong&gt; and &lt;strong&gt;Redirect&lt;/strong&gt;. It should now be somewhat similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BlQduEoF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/okta-add-origin-d38476b395c9bdd5c927dc89f1676bc015f6a135047496755ef7f2dc399a9b2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BlQduEoF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/react-graphql-integration-guide/okta-add-origin-d38476b395c9bdd5c927dc89f1676bc015f6a135047496755ef7f2dc399a9b2d.png" alt="Okta Add Origin" width="677" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, add authentication to the front end. Okta has a library for React; install it by running this in a terminal in the &lt;code&gt;ClientApp&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @okta/okta-react

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

&lt;/div&gt;



&lt;p&gt;Next, go to &lt;code&gt;App.js&lt;/code&gt; in the &lt;code&gt;ClientApp/src&lt;/code&gt;, and add one more import:&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Security&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SecureRoute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ImplicitCallback&lt;/span&gt; &lt;span class="p"&gt;}&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-react&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;Also, surround the existing HTML with a &lt;code&gt;&amp;lt;Security&amp;gt;&lt;/code&gt; -tag, change &lt;code&gt;/fetch-data&lt;/code&gt; to a &lt;code&gt;SecureRoute&lt;/code&gt;, and add a route for &lt;code&gt;/implicit/callback&lt;/code&gt;, so you have 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="nf"&gt;render&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Security&lt;/span&gt; &lt;span class="nx"&gt;issuer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/oauth2/default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="o"&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="nx"&gt;redirectUri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&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;pkce&lt;/span&gt;&lt;span class="o"&gt;=&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="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SecureRoute&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/fetch-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;FetchData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&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="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ImplicitCallback&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Security&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Remember to replace &lt;code&gt;{yourOktaDomain}&lt;/code&gt; with your personal okta domain, which you can find in the Okta Dashboard, and replace &lt;code&gt;{yourClientId}&lt;/code&gt; with the client id you can find in the applications listing.&lt;/p&gt;

&lt;p&gt;If you run the application now, you should not be able to access the Fetch Data page without being logged in. If you are not logged in, you will be redirected to [Okta[(&lt;a href="https://developer.okta.com"&gt;https://developer.okta.com&lt;/a&gt;) for authentication, and then back to the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add API Authorization with Okta
&lt;/h2&gt;

&lt;p&gt;One thing remains, to protect the API for unauthorized access. Add an &lt;code&gt;[Authorize]&lt;/code&gt;-attribute above the &lt;code&gt;Post()&lt;/code&gt;-method in &lt;code&gt;GraphQLController&lt;/code&gt; in the backend. It should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;GraphQLQuery&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now, when logged in, you can access the page, but the call will fail and you won’t get any data. (Watch your web browser’s developer console to see the error message.) To fix that, edit &lt;code&gt;Layout.js&lt;/code&gt; to add this import:&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;withAuth&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-react/dist/withAuth&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;Also, add some lines between &lt;code&gt;const clientParam = ...&lt;/code&gt; and &lt;code&gt;const client = ...&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;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;/graphql&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;myAuth&lt;/span&gt; &lt;span class="o"&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;props&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&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;props&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myAuth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;clientParam&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;operation&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;token&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;myAuth&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="nx"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContext&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="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientParam&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;If you are authenticated, this code will get an access token from Okta, and pass it to the backend, along with all requests sent with the Apollo Client.&lt;/p&gt;

&lt;p&gt;To make sure &lt;code&gt;this.props.auth&lt;/code&gt; is set, wrap this component with the &lt;code&gt;withAuth()&lt;/code&gt;-function that comes with the Okta React authentication library. Add this line to the end of the &lt;code&gt;Layout.js&lt;/code&gt; file:&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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Run, and enjoy your app with easy and secure GraphQL queries to a .NET Core backend!&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More about GraphQL, React, .NET and Okta
&lt;/h2&gt;

&lt;p&gt;Here are some related blog posts to learn more about GraphQL, React, and Okta:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/04/16/graphql-api-with-aspnetcore"&gt;Build a GraphQL API with ASP.NET Core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/08/16/secure-api-spring-boot-graphql"&gt;Build a Secure API with Spring Boot and GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/09/27/build-a-simple-api-service-with-express-and-graphql"&gt;Build a Simple API Service with Express and GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/05/29/build-crud-nodejs-graphql"&gt;Build a CRUD App with Node.js and GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/10/11/build-simple-web-app-with-express-react-graphql"&gt;Build a Simple Web App with Express, React and GraphQL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions about this post, please add a comment below. For more awesome content, follow us on &lt;a href="https://twitter.com/oktadev"&gt;Twitter&lt;/a&gt;, like us on &lt;a href="https://www.facebook.com/oktadevelopers/"&gt;Facebook&lt;/a&gt;, or subscribe to our &lt;a href="https://www.youtube.com/c/oktadev"&gt;YouTube channel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lwu_FNPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://feeds.feedburner.com/%257Er/OktaDeveloperBlog/%257E4/wBt0nRsZC_g" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lwu_FNPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/http://feeds.feedburner.com/%257Er/OktaDeveloperBlog/%257E4/wBt0nRsZC_g" alt="" width="1" height="1"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>graphql</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>ASP.NET Core 3.0 MVC Secure Authentication</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Fri, 15 Nov 2019 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/asp-net-core-3-0-mvc-secure-authentication-3a3</link>
      <guid>https://forem.com/oktadev/asp-net-core-3-0-mvc-secure-authentication-3a3</guid>
      <description>&lt;p&gt;On September 23rd, Microsoft announced the third major release of its .NET Core framework. This new release boasts better performance, support for Windows Desktop apps, improved support for Docker containers, and more. Naturally, I was excited to see this new release and get authentication hooked into it with &lt;a href="https://developer.okta.com" rel="noopener noreferrer"&gt;Okta&lt;/a&gt;! I put together this tutorial to demonstrate how to quickly and securely set up user management with Okta and OIDC (OpenID Connect) in an ASP.NET Core 3.0 application.&lt;/p&gt;

&lt;p&gt;To follow along, you will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet-core/3.0" rel="noopener noreferrer"&gt;DotNet Core 3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;I am using &lt;a href="https://code.visualstudio.com/download" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; on Linux, but you should be able to follow along with &lt;a href="https://visualstudio.microsoft.com/downloads/" rel="noopener noreferrer"&gt;Visual Studio 2019&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;free forever Okta developer account&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scaffold an ASP.NET Core 3.0 MVC Application
&lt;/h2&gt;

&lt;p&gt;To scaffold your new ASP.NET Core 3.0 MVC application, open a terminal window to where you want to store your source code and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new mvc &lt;span class="nt"&gt;-n&lt;/span&gt; AspNetCore3AuthExample

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

&lt;/div&gt;



&lt;p&gt;Then, change into the newly created directory and open up Visual Studio Code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;AspNetCore3AuthExample
code &lt;span class="nb"&gt;.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You should be asked to restore missing components (the &lt;code&gt;.vscode&lt;/code&gt; folder) that will allow you to easily run the app with a quick press of &lt;strong&gt;F5&lt;/strong&gt;. Click &lt;strong&gt;Yes&lt;/strong&gt;, and the folder and files will be added for you. From there, you can run the application and see the base MVC application running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure an Application in Okta
&lt;/h2&gt;

&lt;p&gt;Once you’ve &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;signed up for a free developer account on Okta&lt;/a&gt;, log in to your dashboard and click the &lt;strong&gt;Applications&lt;/strong&gt; menu item, then click the &lt;strong&gt;Add Application&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;On the first screen, choose &lt;strong&gt;Web&lt;/strong&gt; as the platform then click the &lt;strong&gt;Next&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Faspnet-core-3-secure-authentication%2Fokta-choose-platform-c6f3574b7e72c9d189aa92cdda1a642617e1973102652dcb6e71462ae5445ecd.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-jekyll%2Fblog%2Faspnet-core-3-secure-authentication%2Fokta-choose-platform-c6f3574b7e72c9d189aa92cdda1a642617e1973102652dcb6e71462ae5445ecd.png" alt="Okta Choose Platform"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;strong&gt;Application Settings&lt;/strong&gt; screen, give your application a name (I chose “Sample ASP.NET Core 3 OIDC”) and update the &lt;strong&gt;Base URIs&lt;/strong&gt; and &lt;strong&gt;Login redirect URIs&lt;/strong&gt; values to use &lt;code&gt;https&lt;/code&gt; and port 5001, then click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets-jekyll%2Fblog%2Faspnet-core-3-secure-authentication%2Fokta-app-settings-86b1fc83aeaab3d2b39cab15e5e2ca1d74b8ce9f7c96d302a5f09592baeb155d.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-jekyll%2Fblog%2Faspnet-core-3-secure-authentication%2Fokta-app-settings-86b1fc83aeaab3d2b39cab15e5e2ca1d74b8ce9f7c96d302a5f09592baeb155d.png" alt="Okta App Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once complete, you will be redirected to the &lt;strong&gt;General&lt;/strong&gt; tab of the application settings. Click &lt;strong&gt;Edit&lt;/strong&gt; in the top right corner to update a few values.&lt;/p&gt;

&lt;p&gt;First, change the &lt;strong&gt;Login redirect URIs&lt;/strong&gt; value to &lt;code&gt;https://localhost:5001/signin-oidc&lt;/code&gt; and update the &lt;strong&gt;Logout redirect URIs&lt;/strong&gt; value to&lt;code&gt;https://localhost:5001/signout-callback-oidc&lt;/code&gt;, then click &lt;strong&gt;Save&lt;/strong&gt;. These values update the Okta settings to align with what the ASP.NET Core OIDC middleware expects.&lt;/p&gt;

&lt;p&gt;When you first created an Okta account, it automatically set up an AS (Authorization Server) for you called &lt;code&gt;default&lt;/code&gt;. Your next step is to add groups as a claim for authenticated users.&lt;/p&gt;

&lt;p&gt;To view the settings for your default AS, hover over the &lt;strong&gt;API&lt;/strong&gt; menu item at the top of the page and click on the &lt;strong&gt;Authorization Servers&lt;/strong&gt; menu item in the dropdown. From the list of Authorization Servers, choose &lt;strong&gt;default&lt;/strong&gt; to l, see the settings page for the default AS. From the settings page, select the &lt;strong&gt;Claims&lt;/strong&gt; tab and click on the &lt;strong&gt;Add Claim&lt;/strong&gt; button. In the &lt;strong&gt;Add Claim&lt;/strong&gt; dialog add and select the values as shown:&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-jekyll%2Fblog%2Faspnet-core-3-secure-authentication%2Fokta-add-claim-dialog-7db4afa0db8e278dea686f9d0d7931bad397ee1d3920b8b638c8b08a22cd1df9.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-jekyll%2Fblog%2Faspnet-core-3-secure-authentication%2Fokta-add-claim-dialog-7db4afa0db8e278dea686f9d0d7931bad397ee1d3920b8b638c8b08a22cd1df9.png" alt="Okta Add Claim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will add the &lt;code&gt;groups&lt;/code&gt; claim to the ID Token when a user authenticates. Lastly, go to your application’s &lt;strong&gt;General Settings&lt;/strong&gt; and make note of the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt; values. You will be using those to configure your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Your ASP.NET Core 3 MVC App for Authentication
&lt;/h2&gt;

&lt;p&gt;In VS Code, open up the &lt;code&gt;appsettings.Development.json&lt;/code&gt; file and add a new section below the &lt;code&gt;Logging&lt;/code&gt; section so that your completed file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"LogLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Debug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"System"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Information"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Microsoft"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Information"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Okta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ClientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{yourClientId}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ClientSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{yourClientSecret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://{yourOktaDoomain}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostLogoutRedirectUri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://localhost:5001/"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CAUTION:&lt;/strong&gt; It’s important that you never commit sensitive information to your repository. This becomes another attack vector for attackers. For production client IDs and secrets, consider using a Key Management Service (KMS) such as AWS Key Management Service or Azure Key Vault.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Before setting up the OpenID Connect middleware for ASP.NET Core 3, you’ll need to install the NuGet package for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect &lt;span class="nt"&gt;--version&lt;/span&gt; 3.0.0

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

&lt;/div&gt;



&lt;p&gt;Then add a few &lt;code&gt;using&lt;/code&gt; statements to bring in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.Cookies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.OpenIdConnect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.IdentityModel.Protocols.OpenIdConnect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.IdentityModel.Tokens&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TIP:&lt;/strong&gt; You can always just cut and paste the code below and use the key-chord &lt;code&gt;CTRL+.&lt;/code&gt; to have VS Code (and Visual Studio) add the &lt;code&gt;using&lt;/code&gt; statements for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use the &lt;strong&gt;Client ID&lt;/strong&gt; and &lt;strong&gt;Client Secret&lt;/strong&gt; values from the &lt;strong&gt;General Settings&lt;/strong&gt; tab of your application in Okta. Your Okta Domain is listed in the top right corner of your Okta dashboard and looks something like &lt;code&gt;https://dev-123456.okta.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use these values to set up the OIDC configuration in &lt;code&gt;startup.cs&lt;/code&gt;. In the &lt;code&gt;ConfigureServices()&lt;/code&gt; method, before the &lt;code&gt;services.AddControllerWithViews();&lt;/code&gt; call, add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultScheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CookieAuthenticationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultChallengeScheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OpenIdConnectDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCookie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenIdConnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SignInScheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CookieAuthenticationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authority&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Okta:Domain"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/oauth2/default"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequireHttpsMetadata&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Okta:ClientId"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientSecret&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Okta:ClientSecret"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OpenIdConnectResponseType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetClaimsFromUserInfoEndpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"openid"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SaveTokens&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;NameClaimType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;RoleClaimType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"groups"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ValidateIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;While it may look like there’s a lot to unpack here, all you really did was add &lt;code&gt;AddAuthentication()&lt;/code&gt;, &lt;code&gt;AddCookie()&lt;/code&gt;, &lt;code&gt;AddOpenIdConnect()&lt;/code&gt;, and &lt;code&gt;AddAuthorization()&lt;/code&gt;. The rest of it is configuration options.&lt;/p&gt;

&lt;p&gt;Starting from the top, you told ASP.NET’s authentication middleware to use cookies as the authorization scheme and to use OpenID Connect to authenticate. The &lt;code&gt;AddCookie()&lt;/code&gt; method with no options passed to it simply lets the middleware know to use the default setup for cookies.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AddOpenIdConnect()&lt;/code&gt; tells the middleware you want to use OpenID Connect and sets the OpenID Connection options. You told OpenID Connect you’ll be using “Cookies” as the authentication scheme and set values in the options pulled from the &lt;code&gt;appSettings.Development.json&lt;/code&gt; file you just edited. You’ll notice I added &lt;code&gt;oauth2/default&lt;/code&gt; to the &lt;code&gt;Okta:Domain&lt;/code&gt; value - this is the path to your default authorization server.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ResponseType&lt;/code&gt; options lets the middleware know to use the &lt;a href="https://developer.okta.com/docs/guides/implement-auth-code/overview/" rel="noopener noreferrer"&gt;authorization code flow&lt;/a&gt; for authentication. Setting &lt;code&gt;GetClaimsFromUserInfoEndpoint&lt;/code&gt; to true tells the middleware that it will need to make a call to the authorization server’s &lt;code&gt;userinfo&lt;/code&gt; endpoint to populate the user claims.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Scope&lt;/code&gt;s added here are the &lt;code&gt;openid&lt;/code&gt; and &lt;code&gt;profile&lt;/code&gt; scopes. This tells the middleware that you want all the claims contained in those two scopes. &lt;code&gt;SaveTokens&lt;/code&gt; determines whether the access and refresh tokens should be stored in the ASP.NET authentication properties.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TokenValidationParameters&lt;/code&gt; set a few more options for the OIDC set up. The &lt;code&gt;NameClaimType = "name"&lt;/code&gt; lets the middleware know the &lt;code&gt;Name&lt;/code&gt; property for &lt;code&gt;User&lt;/code&gt; will be in the &lt;code&gt;name&lt;/code&gt; claim in the token. The same goes for the &lt;code&gt;RoleClaimType&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since you set the “groups” claim in Okta, you can map it to the roles list of the &lt;code&gt;User&lt;/code&gt; object in your application. Finally, you told OpenID Connect to check that the issuer was valid by making sure it matches the &lt;code&gt;Authority&lt;/code&gt; value from above.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AddAuthorization()&lt;/code&gt; turns on the authorization services for the ASP.NET middleware.&lt;/p&gt;

&lt;p&gt;We have one last change to make in &lt;code&gt;Startup.cs&lt;/code&gt;: add authentication to the &lt;code&gt;Configure()&lt;/code&gt; method. Directly before &lt;code&gt;app.UseAuthorization();&lt;/code&gt;, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Your app is now configured and ready to use OAuth2 and OpenID Connect for authentication and authorization!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authentication to Your ASP.NET Core 3 MVC App
&lt;/h2&gt;

&lt;p&gt;Now that your app is configured to use Okta as the OpenID Connect Identity Provider, you can add the necessary plumbing to the app to actually utilize OpenID Connect for authentication.&lt;/p&gt;

&lt;p&gt;Add a controller called &lt;code&gt;AccountController.cs&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.Cookies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.OpenIdConnect&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DockerPipelineExample.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&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;if&lt;/span&gt;&lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAuthenticated&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;Challenge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OpenIdConnectDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&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;RedirectToAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Home"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SignOutResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OpenIdConnectDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CookieAuthenticationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The two actions here simply kick off an OpenID Connect challenge on &lt;code&gt;Login()&lt;/code&gt; and get the &lt;code&gt;SignOutResult()&lt;/code&gt; in the &lt;code&gt;Logout()&lt;/code&gt; action. You’ve already seen the &lt;code&gt;AuthenticationScheme&lt;/code&gt; string literals in the configuration.&lt;/p&gt;

&lt;p&gt;Now you need to add the user interface elements to kick off login and logout. In the &lt;code&gt;/Views/Shared&lt;/code&gt; folder, add a file called &lt;code&gt;_LoginPartial.cshtml&lt;/code&gt; and add the following code to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@if (User.Identity.IsAuthenticated)
{
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello, @User.Identity.Name&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;  
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"document.getElementById('logout_form').submit();"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"cursor: pointer;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log out&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Account"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Logout"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"logout_form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
}
else
{
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Account"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Login"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log in&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
}

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

&lt;/div&gt;



&lt;p&gt;This will give you a little “chunk” of UI that you can inject into your main page layout. So in the &lt;code&gt;_Layout.cshtml&lt;/code&gt; file, add the login partial right before the close of the &lt;code&gt;div&lt;/code&gt; with a &lt;code&gt;navbar-collapse&lt;/code&gt; class, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-collapse collapse justify-content-between"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav mr-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Index"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Privacy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Privacy&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;partial&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"_LoginPartial"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll also notice I replaced the &lt;code&gt;d-sm-inline-flex flex-sm-row-reverse&lt;/code&gt; classes on the main &lt;code&gt;div&lt;/code&gt; with &lt;code&gt;justify-content-between&lt;/code&gt;. This pushes the login partial to the right of the main menu bar while keeping the menu items on the left and justifying the content between them.&lt;/p&gt;

&lt;p&gt;Now you can fire up the app and log in with your username and password you use for signing in to Okta!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authorization to your ASP.NET Core 3 MVC App
&lt;/h2&gt;

&lt;p&gt;Because you mapped the authenticated user’s roles from the groups claim you set up in Okta, adding authorization becomes drop-dead simple. Add a new action to your &lt;code&gt;HomeController.cs&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Roles&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Everyone"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Everyone&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;View&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 add the using statement for the &lt;code&gt;Authorize&lt;/code&gt; decorator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authorization&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Add a view to the &lt;code&gt;/Views/Home&lt;/code&gt; folder called &lt;code&gt;Everyone.cshtml&lt;/code&gt; with one simple text line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;This page is for people in the "Everyone" group.

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

&lt;/div&gt;



&lt;p&gt;Make sure to add a menu item. I just copied the existing privacy link in &lt;code&gt;_Layout.cshtml&lt;/code&gt; and changed the values like this:&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;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Everyone"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Everyone&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;You can check this isn’t a false positive by changing the &lt;code&gt;Roles&lt;/code&gt; value passed into the &lt;code&gt;Authorize&lt;/code&gt; decorator to something else. I always use &lt;code&gt;Roles="Dancers"&lt;/code&gt; because I &lt;em&gt;know&lt;/em&gt; I’m not in &lt;em&gt;that&lt;/em&gt; group.&lt;/p&gt;

&lt;p&gt;Then when you log in and try to go to the Everyone page, you should be redirected to an &lt;code&gt;/Account/AccessDenied&lt;/code&gt; page. To handle this more gracefully, you can add an action handler to the &lt;code&gt;AccountController&lt;/code&gt; and a view to display a more user-friendly message.&lt;/p&gt;

&lt;p&gt;If you want the final code for this post, you can get it &lt;a href="https://github.com/oktadeveloper/okta-aspnet-core-3-oidc-example" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About OpenID Connect and ASP.NET
&lt;/h2&gt;

&lt;p&gt;If you want to learn more about OAuth2, OpenID Connect, or ASP.NET in general, check out these other great pieces of content!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2017/10/04/aspnet-authorization" rel="noopener noreferrer"&gt;User Authorization in ASP.NET Core with Okta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=t18YB3xDfXI" rel="noopener noreferrer"&gt;An Illustrated Guide to OAuth and OpenID Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/04/03/build-a-crud-app-with-aspnet-22-and-entity-framework" rel="noopener noreferrer"&gt;Build a CRUD App with ASP.NET Core 2.2 and Entity Framework Core&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, feel free to hit us up in the comments below. Also, don’t forget to follow us on &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; and check out our &lt;a href="https://youtube.com/c/oktadev" rel="noopener noreferrer"&gt;YouTube Channel&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/http%3A%2F%2Ffeeds.feedburner.com%2F~r%2FOktaDeveloperBlog%2F~4%2F3oeokjmzVHc" 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/http%3A%2F%2Ffeeds.feedburner.com%2F~r%2FOktaDeveloperBlog%2F~4%2F3oeokjmzVHc"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>security</category>
      <category>tutorial</category>
      <category>oauth</category>
    </item>
    <item>
      <title>Build a CRUD App with ASP.NET Core 2.2 and SQL Server</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Wed, 24 Apr 2019 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/build-a-crud-app-with-asp-net-core-2-2-and-sql-server-3m78</link>
      <guid>https://forem.com/oktadev/build-a-crud-app-with-asp-net-core-2-2-and-sql-server-3m78</guid>
      <description>&lt;p&gt;I’ve always said that you can tell a lot about a person by the kind of music they listen to. Don’t tell me you haven’t had serious doubts about whether you can be friends with someone when you find out that they like a particular band or artist. In that spirit, I created &lt;em&gt;JudgeMyTaste&lt;/em&gt;, an ASP.NET Core web application where people can enter their favorite band or artist so that people on the Internet can judge them openly.&lt;/p&gt;

&lt;p&gt;The combination of ASP.NET and SQL Server is probably the most common pairing in the enterprises that use ASP.NET. With ASP.NET Core and SQL Server both being cross-platform, you don’t &lt;em&gt;have&lt;/em&gt; to run this combination on Windows anymore! I’ll show you how to create a basic CRUD application using ASP.NET Core 2.2 and SQL Server 2016. I’ll be running on Linux, but with the free tools used here, it won’t matter what operating system you’re using!&lt;/p&gt;

&lt;p&gt;The tools I’ll be using that are available for all platforms are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL Server 2016 (I’ll be running on Ubuntu 18.04)&lt;/li&gt;
&lt;li&gt;Visual Studio Code&lt;/li&gt;
&lt;li&gt;Azure Data Studio&lt;/li&gt;
&lt;li&gt;ASP.NET Core 2.2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’ve got all the tools installed for your platform, let’s rock and roll!&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaffold Your ASP.NET Core 2.2 Application
&lt;/h2&gt;

&lt;p&gt;No matter the platform you’re on, the &lt;code&gt;dotnet&lt;/code&gt; CLI is available. The commands used here should be the same for everyone. To scaffold the ASP.NET Core 2.2 MVC application, create a new folder for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;JudgeMyTaste

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

&lt;/div&gt;



&lt;p&gt;Change into that new directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;JudgeMyTaste

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

&lt;/div&gt;



&lt;p&gt;Then run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new mvc

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

&lt;/div&gt;



&lt;p&gt;Then open the new application in VS Code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;code &lt;span class="nb"&gt;.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;When you open the new application in VS Code, you should get a warning in the bottom right corner, asking to add some missing assets. Go ahead and add the missing assets. You’ll see the &lt;code&gt;.vscode&lt;/code&gt; folder added with a &lt;code&gt;launch.json&lt;/code&gt; and a &lt;code&gt;tasks.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i5ZjBryL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/add-vscode-folder-fa54001a5cca1fc313a2103e2b4da0e49a4cccdc401178d6ae0bdf9bbcc8a418.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i5ZjBryL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/add-vscode-folder-fa54001a5cca1fc313a2103e2b4da0e49a4cccdc401178d6ae0bdf9bbcc8a418.png" alt="Add .vscode folder" width="660" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These will allow you to run the application from VS Code. To verify that everything scaffolded properly, run the base application by typing &lt;code&gt;F5&lt;/code&gt;. This will build the application, run it, and open it in a new browser window.&lt;/p&gt;

&lt;p&gt;You may notice a strange error page come up if you’ve never run an ASP.NET Core 2.x application before. By default, ASP.NET Core wants to run on &lt;code&gt;HTTPS&lt;/code&gt;. This is a recommended practice for web applications. You could avoid this message by removing the redirect to &lt;code&gt;HTTPS&lt;/code&gt; in your &lt;code&gt;Startup.cs&lt;/code&gt; or by generating a certificate for your local machine, but this error screen only comes up once in a great while, so I just sidestep it by clicking on &lt;strong&gt;Advanced&lt;/strong&gt; and telling the browser that it’s okay to visit this site even though there is no certificate for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AzrWgO-g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/not-private-advanced-b3245243b35b8b3ead4b3beea765a51b91d212fd7ee53fcf75b6d25073399b0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AzrWgO-g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/not-private-advanced-b3245243b35b8b3ead4b3beea765a51b91d212fd7ee53fcf75b6d25073399b0d.png" alt="Not Private Advanced" width="623" height="592"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For your daily work, it will probably behoove you to create a local certificate for development so that you never have to see this message again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Your SQL Server Database
&lt;/h2&gt;

&lt;p&gt;Open Azure Data Studio and connect to your &lt;code&gt;localhost&lt;/code&gt; server with the &lt;code&gt;SA&lt;/code&gt; password you created when installing SQL Server on your machine. You’ll notice it is arranged very much like VS Code. In the Connections Explorer, you will see &lt;code&gt;localhost&lt;/code&gt; as a connection. Right-click on the connection and choose &lt;strong&gt;New Query&lt;/strong&gt;, which will open a new query window on the right side. Start typing the word &lt;code&gt;CREATE&lt;/code&gt;, and an intellisense drop down will open, and one of the choices will be &lt;code&gt;sqlCreateDatabase&lt;/code&gt;. Choose that option, and a query will be scaffolded with the database name highlighted in the three places that it occurs in the query. You can just start typing the database name “JudgeMyTaste,” and it will be replaced in all three places so that the final query looks like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Create a new database called 'JudgeMyTaste'&lt;/span&gt;
&lt;span class="c1"&gt;-- Connect to the 'master' database to run this snippet&lt;/span&gt;
&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;
&lt;span class="k"&gt;GO&lt;/span&gt;
&lt;span class="c1"&gt;-- Create the new database if it does not exist already&lt;/span&gt;
&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;databases&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;'JudgeMyTaste'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;JudgeMyTaste&lt;/span&gt;
&lt;span class="k"&gt;GO&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now you can just click the green &lt;strong&gt;Run&lt;/strong&gt; arrow at the top of the window to create the database. Simple, no?&lt;/p&gt;

&lt;p&gt;Now when you expand the &lt;strong&gt;Databases&lt;/strong&gt; folder in the Connection Explorer, you will see the &lt;code&gt;JudgeMyTaste&lt;/code&gt; database in the list. Right-click on the new database and choose &lt;strong&gt;New Query&lt;/strong&gt; again. Start typing &lt;code&gt;CREATE&lt;/code&gt; again, and this time choose &lt;code&gt;sqlCreateTable&lt;/code&gt; from the options presented. Again, you can start typing the table name &lt;code&gt;FavoriteBands&lt;/code&gt;, and it will be filled in all the places it occurs in the query.&lt;/p&gt;

&lt;p&gt;You’ll also need to add some other columns to the table. Add the columns for &lt;code&gt;Id&lt;/code&gt;, &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;EnteredBy&lt;/code&gt;, and &lt;code&gt;EnteredOn&lt;/code&gt; so that the query looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Create a new table called '[FavoriteBands]' in schema '[dbo]'&lt;/span&gt;
&lt;span class="c1"&gt;-- Drop the table if it already exists&lt;/span&gt;
&lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="n"&gt;OBJECT_ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'[dbo].[FavoriteBands]'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'U'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FavoriteBands&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;GO&lt;/span&gt;
&lt;span class="c1"&gt;-- Create the table in the specified schema&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;FavoriteBands&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EnteredBy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EnteredOn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;GO&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Then run the query by clicking the green &lt;strong&gt;Run&lt;/strong&gt; arrow as before.&lt;/p&gt;

&lt;p&gt;It’s good practice to create a user specifically for your application to connect with the database. One that only has the permissions that it will need to interact with your database. Here’s a script to create a login and a user for the database and assign that user &lt;code&gt;dbo&lt;/code&gt; permissions to the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="n"&gt;master&lt;/span&gt;

&lt;span class="k"&gt;GO&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;'P@ssw0rd!'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_DATABASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;JudgeMyTaste&lt;/span&gt;

&lt;span class="k"&gt;GO&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="n"&gt;ENABLE&lt;/span&gt;

&lt;span class="k"&gt;GO&lt;/span&gt;

&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="n"&gt;JudgeMyTaste&lt;/span&gt;

&lt;span class="k"&gt;GO&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;LOGIN&lt;/span&gt; &lt;span class="n"&gt;webapp&lt;/span&gt;
&lt;span class="k"&gt;EXEC&lt;/span&gt; &lt;span class="n"&gt;sp_addrolemember&lt;/span&gt; &lt;span class="s1"&gt;'db_owner'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'webapp'&lt;/span&gt;

&lt;span class="k"&gt;GO&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;It might seem like a lot going on here, but it simply creates a login for SQL Server, makes that login a user for the &lt;code&gt;JudgeMyTaste&lt;/code&gt; database, and add it to the &lt;code&gt;db_owner&lt;/code&gt; role for the database. This will allow that login to do all the CRUD operations that the application will need. Now your database is ready to be used by your application!&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect SQL Server to Your ASP.NET Core 2.2 MVC Application
&lt;/h2&gt;

&lt;p&gt;Before anything else, you’ll need the Entity Framework Core NuGet package. To install it, run the following command in the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.EntityFrameworkCore.SqlServer &lt;span class="nt"&gt;--version&lt;/span&gt; 2.2.4

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

&lt;/div&gt;



&lt;p&gt;Start by adding the connection string to your &lt;code&gt;appsettings.json&lt;/code&gt; file in the root of your MVC project, so that it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"LogLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Warning"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHosts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ConnectionStrings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"JudgeMyTasteDatabase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Server=.;Database=JudgeMyTaste;user id=webapp;password=P@ssw0rd!"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Models&lt;/code&gt; folder, create a class file called &lt;code&gt;FavoriteBand.cs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel.DataAnnotations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;JudgeMyTaste.Models&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FavoriteBand&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;EnteredBy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;EnteredOn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This class will be used to work with the &lt;code&gt;FavoriteBand&lt;/code&gt; entries.&lt;/p&gt;

&lt;p&gt;In the root of the project, create a folder called &lt;code&gt;Data&lt;/code&gt; to house the database context for the application. Create a C# file called &lt;code&gt;JudgeMyTasteContext.cs&lt;/code&gt; with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;JudgeMyTaste.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.EntityFrameworkCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;JudgeMyTaste.Data&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JudgeMyTasteContext&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DbContext&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;JudgeMyTasteContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbContextOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JudgeMyTasteContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&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;public&lt;/span&gt; &lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FavoriteBand&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FavoriteBands&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;Startup.cs&lt;/code&gt; file, in the &lt;code&gt;ConfigureServices()&lt;/code&gt; method, right before the &lt;code&gt;services.AddMvc()...&lt;/code&gt; line, add the newly created context with the connection string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;JudgeMyTasteContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JudgeMyTasteDatabase"&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now your database is all hooked into your application. All you need to do is create some way for the user to enter their favorite bands. To get some more scaffolding goodness for the CLI, install the Code Generation tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design

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

&lt;/div&gt;



&lt;p&gt;Now you can scaffold a controller to handle all the CRUD operations for the &lt;code&gt;FavoriteBand&lt;/code&gt; class by running the following command from the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet aspnet-codegenerator controller &lt;span class="nt"&gt;-name&lt;/span&gt; FavoriteBandsController &lt;span class="nt"&gt;-async&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; JudgeMyTaste.Models.FavoriteBand &lt;span class="nt"&gt;-dc&lt;/span&gt; JudgeMyTaste.Data.JudgeMyTasteContext &lt;span class="nt"&gt;-namespace&lt;/span&gt; Controllers &lt;span class="nt"&gt;-outDir&lt;/span&gt; Controllers &lt;span class="nt"&gt;-udl&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is a long one, but if you break it down into its component pieces, it’s easier to understand.&lt;/p&gt;

&lt;p&gt;The first part just calls the &lt;code&gt;dotnet&lt;/code&gt; CLI’s new &lt;code&gt;aspnet-codegenerator&lt;/code&gt; command for a controller. You want the controller’s name to be “FavoriteBandsController” and for the controller actions to all be &lt;code&gt;-async&lt;/code&gt;. The model being used to generate the controller is the &lt;code&gt;JudgeMyTaste.Models.FavoriteBand&lt;/code&gt; class and the database context will be the &lt;code&gt;JudgeMyTaste.Data.JudgeMyTasteContext&lt;/code&gt; class you just created. The namespace and output directory for the controller will be &lt;code&gt;Controllers&lt;/code&gt;, and the &lt;code&gt;-udl&lt;/code&gt; switch tells the generator to use the default layout for the views it will generate (yeah, it’s going to generate views for everything too!). Pretty cool, right?&lt;/p&gt;

&lt;p&gt;Once you run the command, you should see the controller and all its views show up. The only thing left is to create a link so that users can get to the favorite band's section of the site easily.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Views/Shared&lt;/code&gt; folder open the &lt;code&gt;Layout.cshtml&lt;/code&gt; file and add a link to the menu to get to the new section of the site.&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;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"FavoriteBands"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Index"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Favorite Bands&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Now when you run the application, you can click on the &lt;strong&gt;Favorite Bands&lt;/strong&gt; menu item and see a list of all the favorite bands that have been entered. Of course, there aren’t any right now, so add one using the &lt;strong&gt;Create New&lt;/strong&gt; link at the top of the page and see it show up in the listing.&lt;/p&gt;

&lt;p&gt;Now it’s a little cumbersome to add the &lt;strong&gt;EnteredOn&lt;/strong&gt; value manually, and the code generator you used can’t know that you can just add that field to the entry as it’s being saved, so change the &lt;code&gt;Create()&lt;/code&gt; method of the &lt;code&gt;FavoriteBandController&lt;/code&gt; to add it automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// POST: FavoriteBands/Create&lt;/span&gt;
&lt;span class="c1"&gt;// To protect from overposting attacks, please enable the specific properties you want to bind to, for&lt;/span&gt;
&lt;span class="c1"&gt;// more details see http://go.microsoft.com/fwlink/?LinkId=317598.&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ValidateAntiForgeryToken&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Id,Name,EnteredBy"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;FavoriteBand&lt;/span&gt; &lt;span class="n"&gt;favoriteBand&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="n"&gt;ModelState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;favoriteBand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnteredOn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;favoriteBand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&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;RedirectToAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Index&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;View&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;favoriteBand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;The only thing that have changed is that I removed the &lt;code&gt;EnteredOn&lt;/code&gt; field from the &lt;code&gt;Bind&lt;/code&gt; statement in the method signature, and I added the value &lt;code&gt;DateTime.Now&lt;/code&gt; as the value right before saving it to the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authentication to Your ASP.NET Core 2.2 MVC + SQL Server Application
&lt;/h2&gt;

&lt;p&gt;What you have now is &lt;em&gt;okay&lt;/em&gt;, but there’s currently no way to keep users from editing &lt;em&gt;other user’s&lt;/em&gt; entries. We want to make sure to judge people for their favorite band that they actually entered, right?&lt;/p&gt;

&lt;p&gt;No reason to write this yourself. You can easily integrate &lt;a href="https://developer.okta.com"&gt;Okta&lt;/a&gt; to handle the authentication for you and easily:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.okta.com/product/authentication/"&gt;Authenticate&lt;/a&gt; and &lt;a href="https://developer.okta.com/product/authorization/"&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/"&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/"&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/"&gt;product documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sign up for a &lt;a href="https://developer.okta.com/signup/"&gt;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://res.cloudinary.com/practicaldev/image/fetch/s--s_pi3z0L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnetcore-restapi/okta-signup-accab135cb5e7cb06a3446679d6aef0958ea31b3b9444d87ffb2f70e5882d045.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s_pi3z0L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnetcore-restapi/okta-signup-accab135cb5e7cb06a3446679d6aef0958ea31b3b9444d87ffb2f70e5882d045.png" alt="Okta Signup" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have signed up and logged in, you’ll be taken to your dashboard. Make note of your &lt;strong&gt;Org URL&lt;/strong&gt; in the top right corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G7I2qWFu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/okta-org-url-6b1fce3aeb309d0d36fa0bd6d5a7b29013b0b658c476d09ff9bdfd2413dd5b7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G7I2qWFu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/okta-org-url-6b1fce3aeb309d0d36fa0bd6d5a7b29013b0b658c476d09ff9bdfd2413dd5b7a.png" alt="Okta Org URL" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Applications&lt;/strong&gt; menu item at the top, click &lt;strong&gt;Add Application&lt;/strong&gt;, and from the first page of the wizard choose &lt;strong&gt;Web&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VjQF5kcJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/okta-new-webapp-714c67efcc38cda5996afa96fd8aeddbde849738548dd48ff676b31a4aa1827e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VjQF5kcJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/okta-new-webapp-714c67efcc38cda5996afa96fd8aeddbde849738548dd48ff676b31a4aa1827e.png" alt="Okta New Web App" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, change the application name to “Judge My Taste App” and update the &lt;strong&gt;Base URIs&lt;/strong&gt; value and the &lt;strong&gt;Login Redirect URIs&lt;/strong&gt; to reflect the correct port and the fact that you’re running on the &lt;code&gt;HTTPS&lt;/code&gt; scheme.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j6rXu0IP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/okta-app-settings-73f8c1e9334ac11415adc25c788593bf91e3256c9564049b6eb83e534fa15751.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j6rXu0IP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/okta-app-settings-73f8c1e9334ac11415adc25c788593bf91e3256c9564049b6eb83e534fa15751.png" alt="Okta App Settings" width="800" height="943"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click &lt;strong&gt;Done&lt;/strong&gt;, and you’re taken to the application page. On the &lt;strong&gt;General Settings&lt;/strong&gt; tab, click &lt;strong&gt;Edit&lt;/strong&gt; and add a URL to the &lt;strong&gt;Logout Redirect URIs&lt;/strong&gt; with a value of &lt;code&gt;https://localhost:5001/signout/callback&lt;/code&gt;. This is where Okta will redirect back to after the logout call. This is handled by the ASP.NET OIDC Middleware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Your ASP.NET Core 2.2 MVC Application for Authentication
&lt;/h2&gt;

&lt;p&gt;Now you need to tell your application how to use Okta for authentication. The easiest way is to use the ASP.NET SDK from Okta. You can install it from NuGet using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Okta.AspNetCore &lt;span class="nt"&gt;--version&lt;/span&gt; 1.1.5

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

&lt;/div&gt;



&lt;p&gt;Add some configuration values to your &lt;code&gt;appsettings.json&lt;/code&gt; file to that the final file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Logging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"LogLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Warning"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHosts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ConnectionStrings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"JudgeMyTasteDatabase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Server=.;Database=JudgeMyTaste;user id=webapp;password=P@ssw0rd!"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Okta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ClientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{yourClientId}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ClientSecret"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{yourClientSecret}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"OktaDomain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://{yourOktaDomain}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostLogoutRedirectUri"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://localhost:5001/"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;PostLogoutRedirectUri&lt;/code&gt; is the URL that the middleware will redirect to once Okta has redirected back to the &lt;code&gt;signout/callback&lt;/code&gt; URL. You can use any valid URL in the MVC application. Here, I am just redirecting to the root of the application.&lt;/p&gt;

&lt;p&gt;Back in the &lt;code&gt;Startup.cs&lt;/code&gt; file, add the following &lt;code&gt;using&lt;/code&gt; statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Okta.AspNetCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.Cookies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Then at the very beginning of the &lt;code&gt;ConfigureServices()&lt;/code&gt; method add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;oktaMvcOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OktaMvcOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Okta"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oktaMvcOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;oktaMvcOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"openid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"profile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;oktaMvcOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetClaimsFromUserInfoEndpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultAuthenticateScheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CookieAuthenticationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultSignInScheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CookieAuthenticationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultChallengeScheme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OktaDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MvcAuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCookie&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOktaMvc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oktaMvcOptions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This is a pretty dense chunk of code, but most of it is boilerplate for the OIDC middleware that the Okta SDK is built on. The first part just binds all of those configuration values you just added in &lt;code&gt;appsettings.json&lt;/code&gt; to the &lt;code&gt;oktaMvcOptions&lt;/code&gt;. It also adds the scopes you want to receive (which are the OpenID information, the user’s profile, and the user’s email address). It also tells the middleware that it can get the claims from the user info endpoint, which all OIDC identity providers have.&lt;/p&gt;

&lt;p&gt;When the code adds authentication, it tells the OIDC provider to use cookies for storing tokens and that you’ll be sending users to Okta from an MVC application.&lt;/p&gt;

&lt;p&gt;To actually wire up authentication, you need to tell the &lt;code&gt;Configure()&lt;/code&gt; method to use this service you just configured. Right before the &lt;code&gt;app.UseMvc(...)&lt;/code&gt; line, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Okta is now configured in your application! You still need to set up your application to challenge the user (send them to Okta to authenticate).&lt;/p&gt;

&lt;p&gt;Create a new controller in the &lt;code&gt;Controllers&lt;/code&gt; folder called &lt;code&gt;AccountController&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Authentication.Cookies&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Okta.AspNetCore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;JudgeMyTaste.Controllers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&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;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsAuthenticated&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;Challenge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OktaDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MvcAuthenticationScheme&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;RedirectToAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Home"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&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;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SignOutResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OktaDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MvcAuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;CookieAuthenticationDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This will give you a &lt;code&gt;Login()&lt;/code&gt; and &lt;code&gt;Logout()&lt;/code&gt; method to wire up some menu items. Speaking of which, add a new view in &lt;code&gt;Views/Shared&lt;/code&gt; called &lt;code&gt;_LoginPartial.cshtml&lt;/code&gt;. This will house all the code for the login menu items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@if (User.Identity.IsAuthenticated)
{
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav ml-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello, @User.Identity.Name&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;  
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"document.getElementById('logout_form').submit();"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"cursor: pointer;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log out&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Account"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Logout"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"logout_form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
}
else
{
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Account"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Login"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log in&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
}

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

&lt;/div&gt;



&lt;p&gt;Change the main menu in &lt;code&gt;Views/Shared/_Layout.cshtml&lt;/code&gt; to add this in and move the main menu to the left and have the login menu on the far right. The final &lt;code&gt;div&lt;/code&gt; that houses the menu should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-collapse collapse justify-content-between"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-nav mr-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Index"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"Home"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Privacy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Privacy&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-item"&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;class=&lt;/span&gt;&lt;span class="s"&gt;"nav-link text-dark"&lt;/span&gt; &lt;span class="na"&gt;asp-area=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;asp-controller=&lt;/span&gt;&lt;span class="s"&gt;"FavoriteBands"&lt;/span&gt; &lt;span class="na"&gt;asp-action=&lt;/span&gt;&lt;span class="s"&gt;"Index"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Favorite Bands&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;partial&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"_LoginPartial"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class list for the &lt;code&gt;navbar-collapse&lt;/code&gt; has changed to add the &lt;code&gt;justify-content-between&lt;/code&gt; class that will keep the menus apart. The &lt;code&gt;ul&lt;/code&gt;’s class also changed to &lt;code&gt;mr-auto&lt;/code&gt;, which will help keep it left. Lastly, the login partial is added at the end of the menu.&lt;/p&gt;

&lt;p&gt;Don’t just sit there, fire this thing up, and judge me for liking Nickleback!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ouUUhrY9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/final-app-with-auth-running-c3319eccea5ee2dafd2a36e6ef3e74fe2652b174dfa05cea0b734dcc92e5d132.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ouUUhrY9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets-jekyll/blog/aspnet22-sqlserver/final-app-with-auth-running-c3319eccea5ee2dafd2a36e6ef3e74fe2652b174dfa05cea0b734dcc92e5d132.png" alt="Final App With Auth Running" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have a complete CRUD slice built in an ASP.NET Core 2.2 MVC application saving data to a SQL Server database! Now you can take the same path to add things like favorite movie, favorite food, and favorite beverage so that you can easily and completely judge people for their taste online!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About ASP.NET Core 2.2 and SQL Server
&lt;/h2&gt;

&lt;p&gt;If you liked this post, you’ll really like some of the other content here on the Okta Developer Blog!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/04/16/graphql-api-with-aspnetcore"&gt;Build a GraphQL API with ASP.NET Core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/04/10/build-rest-api-with-aspnetcore"&gt;Build a REST API with ASP.NET Core 2.2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/03/26/build-a-crud-app-with-aspnetcore-and-typescript"&gt;Build a CRUD App with ASP.NET Core and TypeScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2019/03/11/node-sql-server"&gt;Build a Secure Node app with SQL Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, feel free to comment below, and don’t forget to follow us on &lt;a href="https://twitter.com/oktadev"&gt;Twitter&lt;/a&gt; and watch us on &lt;a href="https://www.youtube.com/channel/UC5AMiWqFVFxF1q9Ya1FuZ_Q"&gt;YouTube&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>sql</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build and Understand Express Middleware through Examples</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Thu, 13 Sep 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/build-and-understand-express-middleware-through-examples-1ago</link>
      <guid>https://forem.com/oktadev/build-and-understand-express-middleware-through-examples-1ago</guid>
      <description>&lt;p&gt;If you’ve done any significant Node development in the past seven or eight years, you’ve probably used &lt;a href="https://expressjs.com"&gt;Express&lt;/a&gt; to build a web server at some point. While you can create a server in Node without using a library, it doesn’t give you a lot out of the box and can be quite cumbersome to add functionality. Express is a minimalist, “unopinionated” server library and has become the defacto standard for building web apps in Node. To understand Express, you need to understand Express Middleware.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Express Middleware?
&lt;/h2&gt;

&lt;p&gt;Middleware literally means anything you put in the middle of one layer of the software and another. Express middleware are functions that execute during the lifecycle of a request to the Express server. Each middleware has access to the HTTP &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; for each route (or path) it’s attached to. In fact, Express itself is compromised wholly of middleware functions. Additionally, middleware can either terminate the HTTP request or pass it on to another middleware function using &lt;code&gt;next&lt;/code&gt; (more on that soon!) This “chaining” of middleware allows you to compartmentalize your code and create reusable middleware.&lt;/p&gt;

&lt;p&gt;In this article I’ll explain what middleware is, why you would use it, how to use existing Express middleware, and how to write your own middleware for Express.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements to Write Express Middleware
&lt;/h2&gt;

&lt;p&gt;There are a few things you will need installed to create, use, and test Express middleware. First, you will need Node and NPM. To ensure you have them installed, you can 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 -v &amp;amp;&amp;amp; node -v

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

&lt;/div&gt;



&lt;p&gt;You should see the Node and NPM versions you have installed. If you get an error, you need to &lt;a href="https://nodejs.org/en/"&gt;install Node&lt;/a&gt;. I’m using the latest version of both as of the time of this article, which is Node 10.9.0 and NPM 6.4.1, but all the examples should work with Node versions 8+ and NPM versions 5+.&lt;/p&gt;

&lt;p&gt;I will also be using Express version 4.x. This is important because major changes were made from version 3.x to 4.x.&lt;/p&gt;

&lt;p&gt;It will also be helpful to have &lt;a href="https://www.getpostman.com/"&gt;Postman&lt;/a&gt; installed to test routes using any HTTP verbs other than &lt;code&gt;GET&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Express Middleware: The Basics
&lt;/h2&gt;

&lt;p&gt;To get started, you’ll use the most basic of Express’ built-in middleware. This will give you the chance to see how middleware is used, and how Express middleware is structured.&lt;/p&gt;

&lt;p&gt;Create a new project and &lt;code&gt;npm init&lt;/code&gt; it…&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;Create &lt;code&gt;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 plaintext"&gt;&lt;code&gt;const express = require('express');
const app = express();

app.get('/', (req, res, next) =&amp;gt; {
  res.send('Welcome Home');
});

app.listen(3000);

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

&lt;/div&gt;



&lt;p&gt;Run the server via &lt;code&gt;node server.js&lt;/code&gt;, access &lt;code&gt;http://localhost:3000&lt;/code&gt;, and you should see “Welcome Home” printed in your browser.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;app.get()&lt;/code&gt; function is actually built-in Express middleware. You’ll notice the parameters passed to the method are &lt;code&gt;req&lt;/code&gt;, &lt;code&gt;res&lt;/code&gt;, and &lt;code&gt;next&lt;/code&gt;. These are the incoming request, the response being written and a method to call once the middleware is finished. In this case, once the response is sent, the function exits so there is no need to call the &lt;code&gt;next()&lt;/code&gt; method. You could also chain other middleware here by calling the &lt;code&gt;next()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Let’s take a look at a few more examples of the different types of middleware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Express Request Logging Middleware Example
&lt;/h2&gt;

&lt;p&gt;In Express, you can set up middleware to be “global” middleware; meaning it will be called for every incoming request.&lt;/p&gt;

&lt;p&gt;Change the contents of &lt;code&gt;server.js&lt;/code&gt; to:&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 app = express();

app.use((req, res, next) =&amp;gt; {
  console.log(req);
  next();
});

app.get('/', (req, res, next) =&amp;gt; {
  res.send('Welcome Home');
});

app.listen(3000);

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

&lt;/div&gt;



&lt;p&gt;This time, when you go to &lt;code&gt;http://localhost:3000&lt;/code&gt; you should see the same thing in your browser window, but back in the console window you will see the output of the incoming request object.&lt;/p&gt;

&lt;p&gt;The middleware logs out the request object and then calls &lt;code&gt;next()&lt;/code&gt;. The next middleware in the pipeline handles the get request to the root URL and sends back the text response. Using &lt;code&gt;app.use()&lt;/code&gt; means that this is global middleware and will be called for every call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Restrict Express Request Content Type Example
&lt;/h2&gt;

&lt;p&gt;In addition to running middleware for all calls, you could also specify to only run middleware for specific calls.&lt;/p&gt;

&lt;p&gt;Change the &lt;code&gt;server.js&lt;/code&gt; file again to:&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 app = express();

const requireJsonContent = () =&amp;gt; {
  return (req, res, next) =&amp;gt; {
    if (req.headers['content-type'] !== 'application/json') {
        res.status(400).send('Server requires application/json')
    } else {
      next()
    }
  }
}

app.get('/', (req, res, next) =&amp;gt; {
  res.send('Welcome Home');
});

app.post('/', requireJsonContent(), () =&amp;gt; {
  res.send('You sent JSON');
})

app.listen(3000);

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

&lt;/div&gt;



&lt;p&gt;This time, start the server by running:&lt;br&gt;
&lt;/p&gt;

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

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

&lt;/div&gt;



&lt;p&gt;To test this, open up Postman and create a post request to &lt;code&gt;http://localhost:3000&lt;/code&gt;. Don’t set any headers and run the request. You will get back the “Server requires application/json” message.&lt;/p&gt;

&lt;p&gt;Now go back and add the &lt;code&gt;Content-Type&lt;/code&gt; header with a value of &lt;code&gt;application/json&lt;/code&gt; and run the request again. You will get the “You sent JSON” message back from the server.&lt;/p&gt;

&lt;p&gt;This &lt;code&gt;app.post()&lt;/code&gt; method call adds the &lt;code&gt;requireJsonContent()&lt;/code&gt; middleware function to ensure the incoming request payload has a &lt;code&gt;Content-Type&lt;/code&gt; header value set to &lt;code&gt;application/json&lt;/code&gt;. If it doesn’t pass the check, an error response is sent. If it does, the request is then handed off to the next piece of middleware in the chain via the &lt;code&gt;next()&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Third-Party Express Middleware
&lt;/h2&gt;

&lt;p&gt;You’ve built a couple of custom middlewares to far, but there are lots of packages already built to do the things you might normally want to do. In fact, you’ve used the simple routing middleware library by using the &lt;code&gt;app.get()&lt;/code&gt; or &lt;code&gt;app.post()&lt;/code&gt; middleware functions. There are thousands of middleware libraries for doing things like parsing incoming data, routing, and authorization.&lt;/p&gt;

&lt;p&gt;Okta has an Express middleware for OIDC security that I’ll show you to demonstrate using third-party middleware libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Okta for Express Applications
&lt;/h3&gt;

&lt;p&gt;At Okta, our goal is to make &lt;a href="https://developer.okta.com/product/user-management/"&gt;identity management&lt;/a&gt; a lot easier, more secure, and more scalable than what you’re used to. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. Our API enables you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.okta.com/product/authentication/"&gt;Authenticate&lt;/a&gt; and &lt;a href="https://developer.okta.com/product/authorization/"&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/"&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/"&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/"&gt;product documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Okta’s OIDC Express Middleware
&lt;/h2&gt;

&lt;p&gt;To install Okta’s OIDC middleware for Express, 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 @okta/oidc-middleware --save

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

&lt;/div&gt;



&lt;p&gt;Then in the &lt;code&gt;server.js&lt;/code&gt; file, you create an instance if the middleware with some configuration options so that Okta knows how to connect to your Okta application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const oidc = new ExpressOIDC({
  issuer: 'https://{yourOktaDomain}/oauth2/default',
  client_id: '{yourClientId}',
  client_secret: '{yourClientSecret}',
  redirect_uri: 'http://localhost:3000/authorization-code/callback',
  scope: 'openid profile'
});

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

&lt;/div&gt;



&lt;p&gt;You’ll also need to tell Express to use the OIDC middleware router instead of the default router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(oidc.router);

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

&lt;/div&gt;



&lt;p&gt;Then you use it like any other middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/protected', oidc.ensureAuthenticated(), (req, res) =&amp;gt; {
  res.send('Top Secret');
});

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;oidc.ensureAuthenticated()&lt;/code&gt; function is a middleware in the Okta library. It runs a function to see if the current user is logged in. If they are, it calls &lt;code&gt;next()&lt;/code&gt; to let the &lt;code&gt;app.get()&lt;/code&gt; function continue handling the request. If they aren’t it will send back an &lt;code&gt;HTTP 401 (Unauthorized)&lt;/code&gt; response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Middleware Order is Important
&lt;/h2&gt;

&lt;p&gt;When a request is received by Express, each middleware that matches the request is run in the order it is initialized until there is a terminating action (like a response being sent).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aCZqBnhm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/express-middleware-examples/middleware-30b3b30ad54e21d8281719042860f3edd9fb1f40f93150233a08165d908f4631.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aCZqBnhm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://developer.okta.com/assets/blog/express-middleware-examples/middleware-30b3b30ad54e21d8281719042860f3edd9fb1f40f93150233a08165d908f4631.png" alt="Middleware Flow" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So if an error occurs, all middleware that is meant to handle errors will be called in order until one of them calls a terminating event like &lt;code&gt;res.send()&lt;/code&gt; or &lt;code&gt;res.end()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More About Express Middleware
&lt;/h2&gt;

&lt;p&gt;For detailed instructions on setting up the Okta OIDC middleware, you can follow the &lt;a href="https://developer.okta.com/quickstart/#/okta-sign-in-page/nodejs/express"&gt;ExpressJS Quickstart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There is also a list of officially supported Express middleware in this &lt;a href="https://github.com/senchalabs/connect#middleware"&gt;GitHub repo&lt;/a&gt; you can try out and dig into to learn more&lt;/p&gt;

&lt;p&gt;Finally, if you’re interested in learning more about how to use Okta, there’s an &lt;a href="https://github.com/okta/okta-sdk-nodejs"&gt;Okta Node SDK&lt;/a&gt; for implementing more user management functionality in your application.&lt;/p&gt;

&lt;p&gt;As always, I’d love to hear your thoughts and questions in the comments or on twitter @oktadev!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>express</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build a SPA with ASP.NET Core 2.1, Stripe, and Angular 6</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Wed, 08 Aug 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/build-a-spa-with-aspnet-core-21-stripe-and-angular-6-582j</link>
      <guid>https://forem.com/oktadev/build-a-spa-with-aspnet-core-21-stripe-and-angular-6-582j</guid>
      <description>&lt;p&gt;Buying things on the Internet has become a daily activity and is a feature many new projects require. In this tutorial, I will show you how to build an app to sell tickets using an Angular 6 single page app (SPA) using an ASP.NET Core 2.1 backend API. You’ll build both the Angular and ASP.NET Core applications and run them from within VS Code. Let’s get to it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Upgrade to Angular 6
&lt;/h2&gt;

&lt;p&gt;I love to use the latest and greatest when starting a new project. But when you use a project generator (like Angular-CLI, or the DotNetCLI), you may be at the mercy of the latest version the authors of those libraries have added. Right now, the DotNet CLI generates an Angular application with &lt;code&gt;dotnet new angular&lt;/code&gt; gives you an Angular app at about version 4.5, which is about two versions behind the latest. Let me show you how to upgrade the templates and the generated application so that you’re using Angular 6, which is the latest as of the time of this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrade the Angular App Template
&lt;/h3&gt;

&lt;p&gt;Update the DotNet command line tools with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new --install Microsoft.DotNet.Web.Spa.ProjectTemplates::2.1.0

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

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new --install Microsoft.AspNetCore.SpaTemplates::2.1.0-preview1-final

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate the ASP.NET Angular App
&lt;/h3&gt;

&lt;p&gt;Now you can scaffold a new project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet new angular -o ticket-sales-example

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upgrade the Angular App To 6
&lt;/h3&gt;

&lt;p&gt;The closest that gets you is Angular v5.2.0. To update Angular to v6.0.9 (as of this writing) switch to the &lt;code&gt;ClientApp&lt;/code&gt; directory and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng update --all

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

&lt;/div&gt;



&lt;p&gt;This will update the &lt;code&gt;package.json&lt;/code&gt; file; then you need to 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

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

&lt;/div&gt;



&lt;p&gt;If you get a message about &lt;code&gt;@angular/cli&lt;/code&gt; you can update it by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng update @angular/cli

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

&lt;/div&gt;



&lt;p&gt;You may now see some vulnerabilities in your NPM packages. To fix them 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 audit fix

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

&lt;/div&gt;



&lt;p&gt;You may have to run this several times as some of the fixes introduce new vulnerabilities. I was only able to get my vulnerability list down to 6. I still have one low and five moderate vulnerabilities. If you want to get to zero vulnerabilities, you would have to hunt them each down and fix them manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Stripe Account
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to take payments on the web is to use &lt;a href="https://stripe.com/" rel="noopener noreferrer"&gt;Stripe&lt;/a&gt;. You can create a free developer account on &lt;a href="https://dashboard.stripe.com/register" rel="noopener noreferrer"&gt;Stripe’s registration page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you’ve registered, make sure that you go to your dashboard and on the left-hand menu, click the toggle to ensure you are viewing test data. Then click on the &lt;strong&gt;Developers&lt;/strong&gt; menu item and then click &lt;strong&gt;API Keys&lt;/strong&gt;. Copy down the &lt;strong&gt;Publishable key&lt;/strong&gt; to use in your Angular app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Stripe to Your Angular 6 App
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;index.html&lt;/code&gt; file, add a script tag for Stripe’s JavaScript library, right below the &lt;code&gt;app-root&lt;/code&gt; component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="text/javascript" src="https://js.stripe.com/v2/" /&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Also add your publishable key to the Stripe object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;
  Stripe.setPublishableKey('{yourPublishableKey}');
&amp;lt;/script&amp;gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Make sure that your publishable key starts with &lt;code&gt;pk_test_&lt;/code&gt;. If it doesn’t, you’re using the production key, and you don’t want to do that yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Create the Stripe Ticket Registration Page
&lt;/h2&gt;

&lt;p&gt;You can easily scaffold the base registration component with the Angular CLI. Go to a command line and change directories into the &lt;code&gt;src/app&lt;/code&gt; directory. Then run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng generate component registration

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

&lt;/div&gt;



&lt;p&gt;The shorthand for the CLI is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g c registration

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

&lt;/div&gt;



&lt;p&gt;The generate command will generate a folder called &lt;code&gt;registration&lt;/code&gt;, and inside that a &lt;code&gt;registration.compomnent.css&lt;/code&gt;, &lt;code&gt;registration.component.html&lt;/code&gt;, a &lt;code&gt;registration.component.spec.ts&lt;/code&gt;, and a &lt;code&gt;registration.component.ts&lt;/code&gt; file. These are all the basic files for an Angular 6 component. I won’t be covering testing in this tutorial, so you can ignore or delete the &lt;code&gt;registration.component.spec.ts&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;First, add some basic HTML to your &lt;code&gt;registration.component.html&lt;/code&gt; file for displaying tickets. So the final file contents looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h1&amp;gt;Register for SuperDuperConf&amp;lt;/h1&amp;gt;

&amp;lt;div class="ticket conf-only"&amp;gt;
  &amp;lt;span class="title"&amp;gt;Conference Only Pass&amp;lt;/span&amp;gt;
  &amp;lt;span class="price"&amp;gt;$295&amp;lt;/span&amp;gt;
  &amp;lt;button (click)="selectTicket('Conference Only', 295)"&amp;gt;Register Now!&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div class="ticket full"&amp;gt;
  &amp;lt;span class="title"&amp;gt;Full Conference + Workshop Pass&amp;lt;/span&amp;gt;
  &amp;lt;span class="price"&amp;gt;$395&amp;lt;/span&amp;gt;
  &amp;lt;span class="value"&amp;gt;Best Value!&amp;lt;/span&amp;gt;
  &amp;lt;button (click)="selectTicket('Full Conference + Workshop', 395)"&amp;gt;Register Now!&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div class="ticket work-only"&amp;gt;
  &amp;lt;span class="title"&amp;gt;Workshop Only Pass&amp;lt;/span&amp;gt;
  &amp;lt;span class="price"&amp;gt;$195&amp;lt;/span&amp;gt;
  &amp;lt;button (click)="selectTicket('Workshop Only', 195)"&amp;gt;Register Now!&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;div class="alert alert-success" *ngIf="model.successMessage"&amp;gt;{{successMessage}}&amp;lt;/div&amp;gt;
&amp;lt;div class="alert alert-danger" *ngIf="model.errorMessage"&amp;gt;{{errorMessage}}&amp;lt;/div&amp;gt;

&amp;lt;div *ngIf="model.ticket.price"&amp;gt;

  &amp;lt;form (submit)="purchaseTicket()" class="needs-validation" novalidate #regForm="ngForm"&amp;gt;
    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="firstName"&amp;gt;First Name:&amp;lt;/label&amp;gt;
      &amp;lt;input type="text" class="form-control" name="firstName" id="firstName" [(ngModel)]="model.firstName" required #firstName="ngModel"&amp;gt;
      &amp;lt;div [hidden]="firstName.valid || firstName.pristine" class="text-danger"&amp;gt;First Name is required.&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="lastName"&amp;gt;Last Name:&amp;lt;/label&amp;gt;
      &amp;lt;input type="text" class="form-control" name="lastName" id="lastName" [(ngModel)]="model.lastName" required #lastName="ngModel"&amp;gt;
      &amp;lt;div [hidden]="lastName.valid || lastName.pristine" class="text-danger"&amp;gt;Last Name is required.&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="email"&amp;gt;Email Address:&amp;lt;/label&amp;gt;
      &amp;lt;input type="text" class="form-control" name="email" id="email" [(ngModel)]="model.emailAddress" required #email="ngModel"&amp;gt;
      &amp;lt;div [hidden]="email.valid || email.pristine" class="text-danger"&amp;gt;Email Address is required.&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="password"&amp;gt;Password:&amp;lt;/label&amp;gt;
      &amp;lt;input type="password" class="form-control" name="password" id="password" [(ngModel)]="model.password" required #password="ngModel"&amp;gt;
      &amp;lt;div [hidden]="password.valid || password.pristine" class="text-danger"&amp;gt;Password is required.&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="cardNumber"&amp;gt;Card Number:&amp;lt;/label&amp;gt;
      &amp;lt;input type="text" class="form-control" name="cardNumber" id="cardNumber" [(ngModel)]="model.card.number" required&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="form-group form-inline"&amp;gt;
      &amp;lt;label for="expiry"&amp;gt;Expiry:&amp;lt;/label&amp;gt;
      &amp;lt;br/&amp;gt;
      &amp;lt;input type="text" class="form-control mb-1 mr-sm-1" name="expiryMonth" id="expiryMonth" [(ngModel)]="model.card.exp_month"
        required&amp;gt; /
      &amp;lt;input type="text" class="form-control" name="expiryYear" id="expiryYear" [(ngModel)]="model.card.exp_year" required&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div class="form-group"&amp;gt;
      &amp;lt;label for="cvc"&amp;gt;Security Code:&amp;lt;/label&amp;gt;
      &amp;lt;input type="text" class="form-control" name="cvc" id="cvc" [(ngModel)]="model.card.cvc" required&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;button type="submit" class="btn btn-success" [disabled]="!regForm.form.valid"&amp;gt;Pay ${{model.ticket.price / 100}}&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;I know it seems like a lot, but there is a lot of repetition here. The first section lists three tickets that a user can buy to register for the “SuperDuperConf”. The second section is just a form that collects the information needed to register an attendee for the conference.&lt;/p&gt;

&lt;p&gt;The important thing to take note of here is the &lt;code&gt;[(ngModel)]="model.some.thing"&lt;/code&gt; lines of code. That weird sequence of characters around &lt;code&gt;ngModel&lt;/code&gt; is just parentheses inside of square brackets. The parentheses tell Angular that there is an action associated with this field. You see this a lot for click event handlers. It usually looks something like &lt;code&gt;(click)="someEventHandler()"&lt;/code&gt;. It is the same, in that the &lt;code&gt;ngModel&lt;/code&gt; is the handler of the event when the model changes.&lt;/p&gt;

&lt;p&gt;The square brackets are used for updating the DOM when something on the model changes. It is usually seen in something like disabling a button as you did above with &lt;code&gt;[disabled]="!regForm.form.valid"&lt;/code&gt;. It watches the value on the form, and when it is not valid, the button is disabled. Once the form values become valid, the disabled property is removed from the DOM element.&lt;/p&gt;

&lt;p&gt;Now that you have all the fields on the page, you will want to style that ticket section up a bit so that it looks like tickets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.ticket {
  text-align: center;
  display: inline-block;
  width: 31%;
  border-radius: 1rem;
  color: #fff;
  padding: 1rem;
  margin: 1rem;
}

.ticket.conf-only,
.ticket.work-only {
  background-color: #333;
}

.ticket.full {
  background-color: #060;
}

.ticket span {
  display: block;
}

.ticket .title {
  font-size: 2rem;
}

.ticket .price {
  font-size: 2.5rem;
}

.ticket .value {
  font-style: italic;
}

.ticket button {
  border-radius: 0.5rem;
  text-align: center;
  font-weight: bold;
  color: #333;
  margin: 1rem;
}

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

&lt;/div&gt;



&lt;p&gt;These are just three basic ticket types I regularly see for conference registrations.&lt;/p&gt;

&lt;p&gt;Now the meat of the registration page, the TypeScript component. You will need a few things to make the page work. You will need a model to store the values that the user enters, a way for the user to &lt;em&gt;select&lt;/em&gt; a ticket, and a way for the user to &lt;em&gt;pay&lt;/em&gt; for the ticket they have selected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, ChangeDetectorRef, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.css']
})
export class RegistrationComponent {
  public model: any;
  public card: any;

  public errorMessage: string;
  public successMessage: string;

  constructor(
    private http: HttpClient,
    private changeDetector: ChangeDetectorRef,
    @Inject('BASE_URL') private baseUrl: string
  ) {
    this.resetModel();
    this.successMessage = this.errorMessage = null;
  }

  resetModel(): any {
    this.model = {
      firstName: '',
      lastName: '',
      emailAddress: '',
      password: '',
      token: '',
      ticket: { ticketType: '', price: 0 }
    };
    this.card = { number: '', exp_month: '', exp_year: '', cvc: '' };
  }

  selectTicket(ticketType: string, price: number) {
    this.model.ticket = { ticketType, price: price * 100 };
  }

  purchaseTicket() {
    (&amp;lt;any&amp;gt;window).Stripe.card.createToken(
      this.card,
      (status: number, response: any) =&amp;gt; {
        if (status === 200) {
          this.model.token = response.id;
          this.http
            .post(this.baseUrl + 'api/registration', this.model)
            .subscribe(
              result =&amp;gt; {
                this.resetModel();
                this.successMessage = 'Thank you for purchasing a ticket!';
                console.log(this.successMessage);
                this.changeDetector.detectChanges();
              },
              error =&amp;gt; {
                this.errorMessage = 'There was a problem registering you.';
                console.error(error);
              }
            );
        } else {
          this.errorMessage = 'There was a problem purchasing the ticket.';
          console.error(response.error.message);
        }
      }
    );
  }
}

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

&lt;/div&gt;



&lt;p&gt;Even if you’re familiar with Angular, some of this may look foreign. For instance, the &lt;code&gt;BASE_URL&lt;/code&gt; value that is getting injected into the component. It comes from the &lt;code&gt;main.ts&lt;/code&gt; file that the Angular CLI generated. If you look at that file, right below the imports, there is a function called &lt;code&gt;getBaseUrl()&lt;/code&gt; and below that is a &lt;code&gt;providers&lt;/code&gt; section that provides the value from the &lt;code&gt;getBaseUrl()&lt;/code&gt; function, which is just a simple way to inject constant values into components.&lt;/p&gt;

&lt;p&gt;The other thing that might look strange is the &lt;code&gt;purchaseTicket()&lt;/code&gt; function. If you’ve never used Stripe before, the &lt;code&gt;createToken()&lt;/code&gt; method creates a single-use token that you can pass to your server to use in your server-side calls, that way you don’t have to send credit card information to your server, and you can let Stripe handle the security of taking online payments!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the ASP.NET Registration Controller
&lt;/h2&gt;

&lt;p&gt;Now that your Angular app can get a token from Stripe, you’ll want to send that token and the user’s information to the server to charge their card for the ticket. Create a controller in the &lt;code&gt;Controllers&lt;/code&gt; folder in the server-side application root. The contents of the file should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Okta.Sdk;
using Stripe;
using ticket_sales_example.Models;

namespace ticket_sales_example.Controllers
{
  [Produces("application/json")]
  [Route("api/[controller]")]
  public class RegistrationController : ControllerBase
  {
    [HttpPost]
    public async Task&amp;lt;ActionResult&amp;lt;Registration&amp;gt;&amp;gt; CreateAsync([FromBody] Registration registration)
    {
      ChargeCard(registration);
      var oktaUser = await RegisterUserAsync(registration);
      registration.UserId = oktaUser.Id;
      return Ok(registration);
    }

    private async Task&amp;lt;User&amp;gt; RegisterUserAsync(Registration registration)
    {
      var client = new OktaClient();
      var user = await client.Users.CreateUserAsync(
        new CreateUserWithPasswordOptions
        {
          Profile = new UserProfile
          {
            FirstName = registration.FirstName,
            LastName = registration.LastName,
            Email = registration.EmailAddress,
            Login = registration.EmailAddress,
          },
          Password = registration.Password,
          Activate = true
        }
      );

      var groupName = "";
      if (registration.Ticket.TicketType == "Full Conference + Workshop")
      {
        groupName = "FullAttendees";
      }
      if (registration.Ticket.TicketType == "Conference Only")
      {
        groupName = "ConferenceOnlyAttendees";
      }
      if (registration.Ticket.TicketType == "Workshop Only")
      {
        groupName = "WorkshopOnlyAttendees";
      }

      var group = await client.Groups.FirstOrDefault(g =&amp;gt; g.Profile.Name == groupName);
      if (group != null &amp;amp;&amp;amp; user != null)
      {
        await client.Groups.AddUserToGroupAsync(group.Id, user.Id);
      }

      return user as User;
    }

    private StripeCharge ChargeCard(Registration registration)
    {
      StripeConfiguration.SetApiKey("sk_test_uukFqjqsYGxoHaRTOS6R7nFI");

      var options = new StripeChargeCreateOptions
      {
        Amount = registration.Ticket.Price,
        Currency = "usd",
        Description = registration.Ticket.TicketType,
        SourceTokenOrExistingSourceId = registration.Token,
        StatementDescriptor = "SuperDuperConf Ticket"
      };

      var service = new StripeChargeService();
      return service.Create(options);
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;It seems like there is a bit here, but there is only the &lt;code&gt;HttpPost&lt;/code&gt; method &lt;code&gt;CreateAsync()&lt;/code&gt; that is the API endpoint for a &lt;code&gt;POST&lt;/code&gt; to &lt;code&gt;/api/registration&lt;/code&gt;. The other methods are helpers to the endpoint.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ChargeCard()&lt;/code&gt; method does just as the name implies, it charges the user’s credit card using the token that the Angular app got from Stripe and sent to the API. Even though I am setting the Stripe API key with a simple string here for demonstration purposes, you might want to store the key in an environment variable, in a configuration file that doesn’t get checked into source control, or in a key management service like Azure’s Key Vault. This will mitigate the chances that you will accidentally check the test key into your source control and have that end up being deployed to production!&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;RegisterUserAsync()&lt;/code&gt; method handles registering a user with Okta and putting them into a group that corresponds to the ticket that the user is purchasing. This is done in two steps: by creating the user, then finding the group that corresponds with the ticket purchased, and adding that group’s ID to the newly created Okta user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Okta for Your Angular and ASP.NET Core Applications
&lt;/h2&gt;

&lt;p&gt;Dealing with user authentication in web apps is a massive pain for every developer. This is where Okta shines: it helps you secure your web applications with minimal effort.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Okta?
&lt;/h3&gt;

&lt;p&gt;At Okta, our goal is to make &lt;a href="https://developer.okta.com/product/user-management/" rel="noopener noreferrer"&gt;identity management&lt;/a&gt; a lot easier, more secure, and more scalable than what you’re used to. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. Our 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;h3&gt;
  
  
  Create an Okta Application
&lt;/h3&gt;

&lt;p&gt;To get started, you’ll need to create an OpenID Connect application in Okta. Sign up for a forever-free developer account (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%2Fticket-sales-app%2FOktaSignUp-accab135cb5e7cb06a3446679d6aef0958ea31b3b9444d87ffb2f70e5882d045.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%2Fticket-sales-app%2FOktaSignUp-accab135cb5e7cb06a3446679d6aef0958ea31b3b9444d87ffb2f70e5882d045.png" alt="Okta's sign up page."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve logged in and landed on the dashboard page, copy down the Org URL pictured below. You will need this later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2FOktaOrgUrl-38ad1e82ab84ae824e053148055d7b7456c5675d3ef3f27e06874ba47904fcc4.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%2Fticket-sales-app%2FOktaOrgUrl-38ad1e82ab84ae824e053148055d7b7456c5675d3ef3f27e06874ba47904fcc4.png" alt="Okta developer dashboard highlighting the org URL."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then create a new application by browsing to the &lt;strong&gt;Applications&lt;/strong&gt; tab and clicking &lt;strong&gt;Add Application&lt;/strong&gt; , and from the first page of the wizard choose &lt;strong&gt;Single-Page App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2FCreateSpaAppScreenshot-4ae4c8451214a2329e260c16d0f9f0bd6b36a1a5438b8fa6ab4ccf798314b424.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%2Fticket-sales-app%2FCreateSpaAppScreenshot-4ae4c8451214a2329e260c16d0f9f0bd6b36a1a5438b8fa6ab4ccf798314b424.png" alt="Create application wizard with Single Page App selected."&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Name: TicketSalesApp&lt;/li&gt;
&lt;li&gt;Base URIs: &lt;a href="http://localhost:5000" rel="noopener noreferrer"&gt;http://localhost:5000&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Login redirect URIs: &lt;a href="http://localhost:5000/implicit/callback" rel="noopener noreferrer"&gt;http://localhost:5000/implicit/callback&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can leave the other values unchanged, and click &lt;strong&gt;Done&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2Fapplication-settings-9b7640d567f131905f14e462ddd9eacfaf4b6f27f9aac9f99f954109c4287459.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%2Fticket-sales-app%2Fapplication-settings-9b7640d567f131905f14e462ddd9eacfaf4b6f27f9aac9f99f954109c4287459.png" alt="The settings page for the application."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that your application has been created copy down the Client ID and Client secret values on the following page, you’ll need them soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2FOktaAppSecrets-04f9ae1d82ab33072a0de5187e16c23eac3752b8fac955e10d4d2d6377358b12.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%2Fticket-sales-app%2FOktaAppSecrets-04f9ae1d82ab33072a0de5187e16c23eac3752b8fac955e10d4d2d6377358b12.png" alt="The new client ID and client secret."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, create a new authentication token. This will allow your app to talk to Okta to retrieve user information, among other things. To do this, click the &lt;strong&gt;API&lt;/strong&gt; tab at the top of the page followed by the &lt;strong&gt;Create Token&lt;/strong&gt; button. Give your token a name, in this case, “Crud API” would be a good name, then click &lt;strong&gt;Create Token&lt;/strong&gt;. Copy down this token value as you will need it soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2FCrudApiToken-1e8f16398b8899e64b9aa02b9ab180535a3bd27d489cb1e0303212af2914f2bc.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%2Fticket-sales-app%2FCrudApiToken-1e8f16398b8899e64b9aa02b9ab180535a3bd27d489cb1e0303212af2914f2bc.png" alt="Screen showing the API Token."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even though you have a method for registering users, you’ll need to create the groups for the tickets, set up your API to use Okta, and configure it to receive access tokens from users of the Angular app for authorization.&lt;/p&gt;

&lt;p&gt;Start by creating a group for each of the three tickets you’ll be selling. From the Okta dashboard hover over the &lt;strong&gt;Users&lt;/strong&gt; menu item until the drop-down appears and choose &lt;strong&gt;Groups&lt;/strong&gt;. From the Groups page, click the &lt;strong&gt;Add Group&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2Fgroups-listing-f7e41cbcb65825bf6248bfa801a9337e41938709c4e0f2c980bce95ea37898dd.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%2Fticket-sales-app%2Fgroups-listing-f7e41cbcb65825bf6248bfa801a9337e41938709c4e0f2c980bce95ea37898dd.png" alt="List of groups"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Add Group modal that pops up, add a group for each ticket type.&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%2Fticket-sales-app%2Fadd-group-34c4b19eb22f436a30e2c4b1bae4c71810873ed993214825ad8fd7c84c0f5a2b.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%2Fticket-sales-app%2Fadd-group-34c4b19eb22f436a30e2c4b1bae4c71810873ed993214825ad8fd7c84c0f5a2b.png" alt="Add group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you’ll need to add these newly created groups to the ticket sales application. Click on the &lt;strong&gt;Applications&lt;/strong&gt; menu item, and choose the &lt;strong&gt;TicketSalesApp&lt;/strong&gt; from the list of apps. It should open on the &lt;strong&gt;Assignments&lt;/strong&gt; tab. Click on the &lt;strong&gt;Assign&lt;/strong&gt; button and choose &lt;strong&gt;Assign to Groups&lt;/strong&gt; from the button’s drop-down menu. From here, assign each group you just created to the Ticket Sales app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fticket-sales-app%2Fassign-groups-c2415fb0e9165efaee501b0ee2d0c7e3cd231b5adb0b0028b92fc1ee49cdd139.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%2Fticket-sales-app%2Fassign-groups-c2415fb0e9165efaee501b0ee2d0c7e3cd231b5adb0b0028b92fc1ee49cdd139.png" alt="Assign group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Groups to the ID Token
&lt;/h3&gt;

&lt;p&gt;Now you just need to add these groups to the token.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hover over the &lt;strong&gt;API&lt;/strong&gt; menu item and select &lt;strong&gt;Authorization Servers&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the default authorization server (it was created for you when you created your Okta account).&lt;/li&gt;
&lt;li&gt;Choose the Claims tab, and click &lt;strong&gt;Add Claim&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The name of the claim will be “groups”,Select &lt;strong&gt;ID Token&lt;/strong&gt; and &lt;strong&gt;Always&lt;/strong&gt; from the &lt;strong&gt;Include in token type&lt;/strong&gt; setting.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Groups&lt;/strong&gt; from the &lt;strong&gt;Value Type&lt;/strong&gt; setting, and &lt;strong&gt;Regex&lt;/strong&gt; from the &lt;strong&gt;Filter&lt;/strong&gt; setting.&lt;/li&gt;
&lt;li&gt;In the text box type &lt;code&gt;.*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally, make sure the &lt;strong&gt;Disable claim&lt;/strong&gt; checkbox is unchecked and that the &lt;strong&gt;Any scope&lt;/strong&gt; radio button is selected in the &lt;strong&gt;Include in&lt;/strong&gt; setting.&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%2Fticket-sales-app%2FAddGroupsToTokenScreenshot-c78196f6d97cb7d76120047046bf9c59468fc758f001e08b175de017db8c58bf.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%2Fticket-sales-app%2FAddGroupsToTokenScreenshot-c78196f6d97cb7d76120047046bf9c59468fc758f001e08b175de017db8c58bf.png" alt="Add Groups to Token Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Okta to Your Angular Application
&lt;/h2&gt;

&lt;p&gt;To set up your Angular application to use Okta for authentication, you’ll need to install the Angular SDK and the &lt;code&gt;rxjs&lt;/code&gt; compatibility package.&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 @okta/okta-angular rxjs-compat@6 --save

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

&lt;/div&gt;



&lt;p&gt;Add the components to your &lt;code&gt;app.module.ts&lt;/code&gt; file in &lt;code&gt;src/app&lt;/code&gt; by first importing them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  OktaCallbackComponent,
  OktaAuthModule,
  OktaAuthGuard
} from '@okta/okta-angular';

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

&lt;/div&gt;



&lt;p&gt;Now add a configuration variable right below the import statements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config = {
  issuer: 'https://{yourOktaDomain}/oauth2/default',
  redirectUri: 'http://localhost:5000/implicit/callback',
  clientId: '{yourClientId}'
};

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

&lt;/div&gt;



&lt;p&gt;Add the callback route to the routes in the &lt;code&gt;imports&lt;/code&gt; section of the &lt;code&gt;@NgModule&lt;/code&gt; declaration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ path: 'implicit/callback', component: OktaCallbackComponent }

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

&lt;/div&gt;



&lt;p&gt;That’s all for now in the Angular application. Now let’s get the ASP.NET Core app set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Okta to Your ASP.NET Core API
&lt;/h2&gt;

&lt;p&gt;Now you need to let the API know two things: how to get the user’s identity from an access token (when one is sent) and how to call Okta for user management.&lt;/p&gt;

&lt;p&gt;Start by adding the Okta Nuget package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet add package Okta.Sdk

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

&lt;/div&gt;



&lt;p&gt;For the ASP.NET Core application, the best thing to do is set up a file in your home folder to store the configuration. Okta’s SDK will pick the settings up for you, and you’ll never accidentally check them into source control!&lt;/p&gt;

&lt;p&gt;In your home directory, create a .okta folder and add a file called okta.yaml. Your home folder will depend on your operating system. For *nix variants like Linux or macOS it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.okta/okta.yaml

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

&lt;/div&gt;



&lt;p&gt;for Windows environments it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%userprofile%\.okta\okta.yaml

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

&lt;/div&gt;



&lt;p&gt;YAML is just a file format for configuration. The okta.yaml file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;okta:
  client:
    orgUrl: "https://dev-846291.oktapreview.com/"
    token: "{yourApiToken}"

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

&lt;/div&gt;



&lt;p&gt;In the ConfigureServices() method before the services.AddMvc() line, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddAuthentication(sharedOptions =&amp;gt;
{
  sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =&amp;gt;
{
  options.Authority = "https://{yourOktaDomain}/oauth2/default";
  options.Audience = "api://default";
});

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

&lt;/div&gt;



&lt;p&gt;And in the Configure() method before the app.UseMvc() line add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.UseAuthentication();

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

&lt;/div&gt;



&lt;p&gt;That’s it! Now your ASP.NET Core app will take that bearer token, get the user’s information from Okta add them to the User object so you can get the currently requesting user’s data. It will also use the API token stored in the &lt;code&gt;okta.yaml&lt;/code&gt; file when registering users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show the Tickets in Your Angular App
&lt;/h2&gt;

&lt;p&gt;Now that users can purchase a ticket, you’ll want them to be able to log in and see their purchased ticket. To do this, generate a profile component using Angular’s CLI. From the &lt;code&gt;src/app&lt;/code&gt; folder of the client app, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ng g c profile

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

&lt;/div&gt;



&lt;p&gt;Again, this is just shorthand for &lt;code&gt;ng generate component profile&lt;/code&gt;, which will generate all the base files for the profile component. The &lt;code&gt;profile.component.ts&lt;/code&gt; file should have the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, OnInit } from '@angular/core';
import { OktaAuthService } from '@okta/okta-angular';
import 'rxjs/Rx';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
  user: any;
  ticket: string;

  constructor(private oktaAuth: OktaAuthService) {}

  async ngOnInit() {
    this.user = await this.oktaAuth.getUser();
    if (this.user.groups.includes('FullAttendees')) {
      this.ticket = 'Full Conference + Workshop';
    } else if (this.user.groups.includes('ConferenceOnlyAttendees')) {
      this.ticket = 'Conference Only';
    } else if (this.user.groups.includes('WorkshopOnlyAttendees')) {
      this.ticket = 'Workshop Only';
    } else {
      this.ticket = 'None';
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;This does two things: it gets the currently logged in user and translates the group name into a displayable string representation of the ticket type purchased. The &lt;code&gt;profile.component.html&lt;/code&gt; file is straightforward:&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;h1&amp;gt;{{user.name}}&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;
  Your Puchased Ticket: {{ticket}}
&amp;lt;/p&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;The last thing to do is to add a protected route to the profile page in the &lt;code&gt;app.module.ts&lt;/code&gt;. I added mine right above the callback route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  path: 'profile',
  component: ProfileComponent,
  canActivate: [OktaAuthGuard]
},

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

&lt;/div&gt;



&lt;p&gt;You can now sell tickets, and the users can log in and see which ticket they have once they’ve purchased one. You’re ready to hold your event!&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn More about ASP.NET
&lt;/h2&gt;

&lt;p&gt;Check out our other Angular and .NET posts on the Okta developer blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ibrahim creates a &lt;a href="https://developer.okta.com/blog/2018/07/27/build-crud-app-in-aspnet-framework-webapi-and-angular" rel="noopener noreferrer"&gt;CRUD app with an ASP.NET Framework 4.x API in his post&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Build a basic &lt;a href="https://developer.okta.com/blog/2018/07/02/build-a-secure-crud-app-with-aspnetcore-and-react" rel="noopener noreferrer"&gt;CRUD app using Angular and ASP.NET Core&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;If you would like to use &lt;a href="https://developer.okta.com/blog/2018/08/02/aspnet-core-angular-crud" rel="noopener noreferrer"&gt;React instead of Angular for your CRUD app, I’ve got you covered&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Get nitty-gritty on &lt;a href="https://developer.okta.com/blog/2018/03/23/token-authentication-aspnetcore-complete-guide" rel="noopener noreferrer"&gt;token authentication in ASP.NET Core&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Get your project out into the world by &lt;a href="https://developer.okta.com/blog/2018/06/19/deploy-your-aspnet-core-app-to-azure" rel="noopener noreferrer"&gt;deploying it to Azure, the right way&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, if you have any comments or questions, feel free to leave a comment below. Don’t forget to follow us on Twitter &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;@oktadev&lt;/a&gt; and &lt;a href="https://www.facebook.com/oktadevelopers" rel="noopener noreferrer"&gt;on Facebook&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>spa</category>
      <category>aspnetcore</category>
      <category>angular</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build a Secure CRUD App with ASP.NET Core and React</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Mon, 02 Jul 2018 05:00:00 +0000</pubDate>
      <link>https://forem.com/oktadev/build-a-secure-crud-app-with-aspnet-core-and-react-46ha</link>
      <guid>https://forem.com/oktadev/build-a-secure-crud-app-with-aspnet-core-and-react-46ha</guid>
      <description>&lt;p&gt;These days it’s prevalent to have a “back-end” and a “front-end” allowing two (or more) teams to work on a project. Microsoft’s latest version of the ASP.NET Core framework is cross-platform and performant. Pairing it with the power and flexibility of Facebook’s React framework makes it a pretty stable platform. In this tutorial, I will show you how to build a secure CRUD (Create, Read, Update, and Delete) application using these two powerful technologies.&lt;/p&gt;

&lt;p&gt;When conferences need speakers, they sometimes put out a public speaker “Call for Presentations” or CFP. Potential speakers then submit talks that they’d like to give at the conference, and the organizers pick from those submissions which talks they’d like to have presented at their conference.&lt;/p&gt;

&lt;p&gt;The application you’ll be building is a speaker submission page. It will allow users to register for an account, log in and submit potential conference sessions. They will also need to be able to log in later and update their submissions or, if they then are unable to present that talk, delete the submission.&lt;/p&gt;

&lt;p&gt;The architecture for the application will be a React front-end application fed data from an ASP.NET Core Web API. For demonstration purposes, you’ll use Entity Framework’s in-memory database option. It is an excellent option for proof-of-concept applications. You can change it to use a SQL Server or PostgreSQL database later by just changing one line of configuration code!&lt;/p&gt;

&lt;h2&gt;
  
  
  What You’ll Need to Get Started
&lt;/h2&gt;

&lt;p&gt;There are a few tools you will need to get, develop and run the application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Git command line&lt;/li&gt;
&lt;li&gt;The .NET Framework 2+&lt;/li&gt;
&lt;li&gt;Node and NPM&lt;/li&gt;
&lt;li&gt;Visual Studio or VS Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am developing the application on a Linux laptop. Most of the commands will be the same whether you are on Linux, macOS, or Windows. The only thing that will be different is the home folder where your Okta credentials are stored for the ASP.NET Core API, and I will put both paths in the examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get the Base ASP.NET Core and React Application
&lt;/h2&gt;

&lt;p&gt;To get the basic scaffolding for the app in place, start by cloning the basic React and ASP.NET Core application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:oktadeveloper/dotnetcore-react-crud-example

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

&lt;/div&gt;



&lt;p&gt;Then create a new branch we’ll use to turn the shell into a fully CRUD application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout -b crud-app

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Set Up Your Okta Application
&lt;/h2&gt;

&lt;p&gt;Dealing with user authentication in web apps is a massive pain for every developer. This is where Okta shines: it helps you secure your web applications with minimal effort. To get started, you’ll need to create an OpenID Connect application in Okta. Sign up for a forever-free developer account (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%2Fcrud-aspnet-core-react%2Fokta-signup-accab135cb5e7cb06a3446679d6aef0958ea31b3b9444d87ffb2f70e5882d045.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%2Fcrud-aspnet-core-react%2Fokta-signup-accab135cb5e7cb06a3446679d6aef0958ea31b3b9444d87ffb2f70e5882d045.png" alt="Okta Signup Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve logged in and landed on the dashboard page, copy down the Org URL pictured below. You will need this later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fcrud-aspnet-core-react%2Fokta-org-url-38ad1e82ab84ae824e053148055d7b7456c5675d3ef3f27e06874ba47904fcc4.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%2Fcrud-aspnet-core-react%2Fokta-org-url-38ad1e82ab84ae824e053148055d7b7456c5675d3ef3f27e06874ba47904fcc4.png" alt="Org Url Dashboard Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then create a new application by browsing to the &lt;strong&gt;Applications&lt;/strong&gt; tab and clicking &lt;strong&gt;Add Application&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fcrud-aspnet-core-react%2Fokta-app-dashboard-28e02cba86bd97f0898d883d5a416ac6581d56d2207623f5ae94c816103976e2.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%2Fcrud-aspnet-core-react%2Fokta-app-dashboard-28e02cba86bd97f0898d883d5a416ac6581d56d2207623f5ae94c816103976e2.png" alt="Application Dashboard Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the wizard, choose the &lt;strong&gt;Single-Page App&lt;/strong&gt; option for the React app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fcrud-aspnet-core-react%2Fsingle-page-app-679f5e1ea17bc95523dfd741084c8af93011042aa300eda87e6a515a6821ffe6.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%2Fcrud-aspnet-core-react%2Fsingle-page-app-679f5e1ea17bc95523dfd741084c8af93011042aa300eda87e6a515a6821ffe6.png" alt="App Wizard screenshot with Single Page App Selected"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name:&lt;/strong&gt; ReactCrud&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base URIs:&lt;/strong&gt; &lt;code&gt;http://localhost:5000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login redirect URIs:&lt;/strong&gt; &lt;code&gt;http://localhost:5000/implicit/callback&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fcrud-aspnet-core-react%2Fapplication-settings-3f9b43a78e47b54c1cb0abc3fed7f849528823dd6bd58164c2b74962826c2754.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%2Fcrud-aspnet-core-react%2Fapplication-settings-3f9b43a78e47b54c1cb0abc3fed7f849528823dd6bd58164c2b74962826c2754.png" alt="Application Settings Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that your application has been created, copy down the Client ID and Client secret values on the following page, you’ll need them soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fcrud-aspnet-core-react%2Fokta-app-secrets-04f9ae1d82ab33072a0de5187e16c23eac3752b8fac955e10d4d2d6377358b12.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%2Fcrud-aspnet-core-react%2Fokta-app-secrets-04f9ae1d82ab33072a0de5187e16c23eac3752b8fac955e10d4d2d6377358b12.png" alt="Application Secrets Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, create a new authentication token. This will allow your app to talk to Okta to retrieve user information, among other things. To do this, click the &lt;strong&gt;API&lt;/strong&gt; tab at the top of the page followed by the &lt;strong&gt;Create Token&lt;/strong&gt; button. Give your token a name, in this case “Crud API” would be a good name, then click &lt;strong&gt;Create Token&lt;/strong&gt;. Copy down this token value as you will need it soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fcrud-aspnet-core-react%2Fcreate-api-token-1e8f16398b8899e64b9aa02b9ab180535a3bd27d489cb1e0303212af2914f2bc.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%2Fcrud-aspnet-core-react%2Fcreate-api-token-1e8f16398b8899e64b9aa02b9ab180535a3bd27d489cb1e0303212af2914f2bc.png" alt="API Token Creation Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve created your new Okta application, you’ll want to store the configuration information in your React and ASP.NET Core applications.&lt;/p&gt;

&lt;p&gt;For the React application, create a file in the &lt;code&gt;/ClientApp&lt;/code&gt; folder called &lt;code&gt;app.config.js&lt;/code&gt;. This will export a simple JSON object with the configuration information for your React application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
  url: 'https://{yourOktaDomain}',
  issuer: 'https://{yourOktaDomain}/oauth2/default',
  redirect_uri: window.location.origin + '/implicit/callback',
  client_id: '{yourClientID}'
}

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

&lt;/div&gt;



&lt;p&gt;For the ASP.NET Core application, the best thing to do is set up a file in your home folder to store the configuration. Okta’s SDK will pick the settings up for you, and you’ll never accidentally check them into source control!&lt;/p&gt;

&lt;p&gt;In your home directory, create an &lt;code&gt;.okta&lt;/code&gt; folder and add a file called &lt;code&gt;okta.yaml&lt;/code&gt;. Your home folder will depend on your operating system. For *nix variants like Linux or macOS it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.okta/okta.yaml

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

&lt;/div&gt;



&lt;p&gt;for Windows environments it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%userprofile%\.okta\okta.yaml

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

&lt;/div&gt;



&lt;p&gt;YAML, is just a file format for configuration. The &lt;code&gt;okta.yaml&lt;/code&gt; file looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;okta:
  client:
    orgUrl: "https://{yourOktaDomain}/"
    token: "{yourApiToken}"

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

&lt;/div&gt;



&lt;p&gt;Now you’re ready to get the dependencies set up!&lt;/p&gt;

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

&lt;p&gt;To take full advantage of Okta for identity management, you’ll need Okta’s React SDK and the generic JavaScript package it depends on. To install, from the command line 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 @okta/okta-react@1.0.2 --save

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

&lt;/div&gt;



&lt;p&gt;Now you’re ready to write some code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Registration to the React Application
&lt;/h2&gt;

&lt;p&gt;Start by adding a folder for the authentication components you’ll be creating. In the &lt;code&gt;/ClientApp/components&lt;/code&gt; folder, create a folder called &lt;code&gt;auth&lt;/code&gt;, and create a &lt;code&gt;RegisterPage.js&lt;/code&gt; file inside it. The page will be a component that is wrapped by the &lt;code&gt;withAuth&lt;/code&gt; higher-order component. To learn more about higher-order components, read the docs &lt;a href="https://reactjs.org/docs/higher-order-components.html" rel="noopener noreferrer"&gt;on React’s website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The final &lt;code&gt;RegisterPage.js&lt;/code&gt; component will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react'; 
import { Redirect} from 'react-router-dom';
import OktaAuth from '@okta/okta-auth-js';
import { withAuth } from '@okta/okta-react';

import config from '../../app.config';

export default withAuth(class RegisterPage extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      firstName: '',
      lastName: '',
      email: '',
      password: '',
      sessionToken: null,
      registered: false
    };
    this.oktaAuth = new OktaAuth({ url: config.url });
    this.checkAuthentication = this.checkAuthentication.bind(this);
    this.checkAuthentication();

    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleFirstNameChange = this.handleFirstNameChange.bind(this);
    this.handleLastNameChange = this.handleLastNameChange.bind(this);
    this.handleEmailChange = this.handleEmailChange.bind(this);
    this.handlePasswordChange = this.handlePasswordChange.bind(this);    
  }

  async checkAuthentication() {
    const sessionToken = await this.props.auth.getIdToken();
    if (sessionToken) {
      this.setState({ sessionToken });
    }
  }

  componentDidUpdate() {
    this.checkAuthentication();
  }

  handleFirstNameChange(e){
    this.setState({firstName:e.target.value});
  }
  handleLastNameChange(e) {
    this.setState({ lastName: e.target.value });
  }
  handleEmailChange(e) {
    this.setState({ email: e.target.value });
  }
  handlePasswordChange(e) {
    this.setState({ password: e.target.value });
  }

  handleSubmit(e){
    e.preventDefault();
    fetch('/api/users', { 
      method: 'POST', 
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(this.state)
    }).then(user =&amp;gt; {
      this.setState({ registered: true });
    })
    .catch(err =&amp;gt; console.log);
  }

  render(){
    if (this.state.sessionToken) {
      this.props.auth.redirect({ sessionToken: this.state.sessionToken });
      return null;
    }

    if(this.state.registered === true){
      return &amp;lt;Redirect to="/login"/&amp;gt;
    }

    return(
      &amp;lt;form onSubmit={this.handleSubmit} className="registration"&amp;gt;
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input type="email" id="email" value={this.state.email} 
          onChange={this.handleEmailChange}/&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;First Name:&amp;lt;/label&amp;gt;
          &amp;lt;input type="text" id="firstName" value={this.state.firstName} 
          onChange={this.handleFirstNameChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Last Name:&amp;lt;/label&amp;gt;
          &amp;lt;input type="text" id="lastName" value={this.state.lastName} 
          onChange={this.handleLastNameChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Password:&amp;lt;/label&amp;gt;
          &amp;lt;input type="password" id="password" value={this.state.password} 
          onChange={this.handlePasswordChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-actions"&amp;gt;
          &amp;lt;input type="submit" id="submit" className="btn btn-primary" value="Register"/&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/form&amp;gt;
    );
  }

});

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

&lt;/div&gt;



&lt;p&gt;I know this looks like a lot, but most of it is pretty simple. Let’s break it down into categories: state, handlers, and Okta stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle User State in the React Application
&lt;/h2&gt;

&lt;p&gt;The state declared in the constructor, has six properties. The &lt;code&gt;firstName&lt;/code&gt;, &lt;code&gt;lastName&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;password&lt;/code&gt; are the required fields for registering an account in Okta.. The &lt;code&gt;sessionToken&lt;/code&gt; property is there to use when checking to see if the user has mistakenly come to the page when they are already logged in. It’s checked using the &lt;code&gt;checkAuthentication()&lt;/code&gt; method that runs from the constructor. The &lt;code&gt;render()&lt;/code&gt; method checks the value of the &lt;code&gt;sessionToken&lt;/code&gt;, and if a session token exists, redirects the user is redirected to the homepage.&lt;/p&gt;

&lt;p&gt;There are many handler functions in the component: one for each property the user will edit in the form, and one for handling the submission of the registration form. The handlers for each field on the form are simple. They update the state when the fields’ values are changed by the user. The form submission handler does exactly what you’d expect; it submits the information in the form to a URL so that the API can handle creating the user in Okta.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;withAuth&lt;/code&gt; higher-order component wraps the &lt;code&gt;RegisterPage&lt;/code&gt; component and adds an &lt;code&gt;auth&lt;/code&gt; object to the props which can do things like &lt;code&gt;getIdToken()&lt;/code&gt; for the currently logged in user. Any component that needs to get the current user or information about them will need to be wrapped by the &lt;code&gt;withAuth&lt;/code&gt; higher-order component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Registration to the ASP.NET Core API
&lt;/h2&gt;

&lt;p&gt;For user registration to work, you’ll need to add that endpoint you’re calling in the registration page. This endpoint will call to Okta and add a user using the Okta .NET SDK.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Controllers&lt;/code&gt; folder add a controller called &lt;code&gt;UserController.cs&lt;/code&gt;. Then you’ll add a &lt;code&gt;POST&lt;/code&gt; action to the controller to handle getting the user’s registration information and creating the user in Okta.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.AspNetCore.Mvc;
using Okta.Sdk;
using Okta.Sdk.Configuration;
using okta_dotnetcore_react_example.Models;

namespace okta_dotnetcore_react_example.Controllers
{
  [Route("api/[controller]")]
  public class UsersController : Controller
  {
    [HttpPost]
    public async void Post([FromBody]Registration reg)
    {

      var oktaClient = new OktaClient();
      var user = await oktaClient.Users.CreateUserAsync(
          new CreateUserWithPasswordOptions
          {
            Profile = new UserProfile
            {
              FirstName = reg.FirstName,
              LastName = reg.LastName,
              Email = reg.Email,
              Login = reg.Email
            },
            Password = reg.Password,
            Activate = true
          }
      );
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;You’ll also need the &lt;code&gt;Registration.cs&lt;/code&gt; file in the &lt;code&gt;Models&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;namespace okta_dotnetcore_react_example.Models
{
    public class Registration
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
    }
}

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

&lt;/div&gt;



&lt;p&gt;Nothing complicated here, just a set of properties for holding registration information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authentication to the React Application
&lt;/h2&gt;

&lt;p&gt;Now you’ll need to add the ability for users to authenticate with their newly minted account. To do this, add a file to the &lt;code&gt;/ClientApp/auth&lt;/code&gt; folder called &lt;code&gt;LoginPage.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The login page willbe wrapped in the &lt;code&gt;withAuth&lt;/code&gt; component, but will also need the &lt;code&gt;OktaAuth&lt;/code&gt; component from the generic JavaScript library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import OktaAuth from '@okta/okta-auth-js';
import { withAuth } from '@okta/okta-react';

export default withAuth(class LoginPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sessionToken: null,
      error: null,
      username: '',
      password: ''
    }

    this.oktaAuth = new OktaAuth({ url: props.baseUrl });

    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleUsernameChange = this.handleUsernameChange.bind(this);
    this.handlePasswordChange = this.handlePasswordChange.bind(this);
  }

  handleSubmit(e) {
    e.preventDefault();
    this.oktaAuth.signIn({
      username: this.state.username,
      password: this.state.password
    })
      .then(res =&amp;gt; this.setState({
        sessionToken: res.sessionToken
      }))
      .catch(err =&amp;gt; {
        this.setState({error: err.message});
        console.log(err.statusCode + ' error', err)
      });
  }

  handleUsernameChange(e) {
    this.setState({ username: e.target.value });
  }

  handlePasswordChange(e) {
    this.setState({ password: e.target.value });
  }

  render() {
    if (this.state.sessionToken) {
      this.props.auth.redirect({ sessionToken: this.state.sessionToken });
      return null;
    }

    const errorMessage = this.state.error ? 
    &amp;lt;span className="error-message"&amp;gt;{this.state.error}&amp;lt;/span&amp;gt; : 
    null;

    return (
      &amp;lt;form onSubmit={this.handleSubmit} className="login"&amp;gt;
        {errorMessage}
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Username:&amp;lt;/label&amp;gt;
          &amp;lt;input
            id="username" type="text"
            value={this.state.username}
            onChange={this.handleUsernameChange} /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Password:&amp;lt;/label&amp;gt;
          &amp;lt;input
            id="password" type="password"
            value={this.state.password}
            onChange={this.handlePasswordChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-actions"&amp;gt;
        &amp;lt;input id="submit" type="submit" value="Submit" /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/form&amp;gt;
    );
  }
});

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

&lt;/div&gt;



&lt;p&gt;Now that you’ve built the registration page component, this one should be easier to understand. The state has the &lt;code&gt;sessionToken&lt;/code&gt; again, this time for checking after the user is logged in. The &lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; properties are used for the form, and the &lt;code&gt;error&lt;/code&gt; property allows you to store authentication error messages to display to users.&lt;/p&gt;

&lt;p&gt;The handlers are very similar to those in the registration component in that they update the form values in the state as the user updates them and the &lt;code&gt;handleSubmit()&lt;/code&gt; function once again handles the action from the form’s submit button.&lt;/p&gt;

&lt;p&gt;There is a little more Okta functionality here as well. In the constructor, there is a new &lt;code&gt;OktaAuth&lt;/code&gt; object created with a base URL (from props), and the form submission handler uses it. When the form is submitted, the &lt;code&gt;OktaAuth&lt;/code&gt; object’s &lt;code&gt;signIn()&lt;/code&gt; method is called with the username and password that the user has entered and a response with a session token is returned via a promise. In the &lt;code&gt;then&lt;/code&gt; of the promise, the method adds the session token to the session state. The Okta SDK will handle storing the token for you, which you will set up next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a Profile Page to the React Application
&lt;/h2&gt;

&lt;p&gt;Once the user is logged in, you’ll need somewhere for them to view the list of their submissions, so create a new file in the &lt;code&gt;/ClientApp/components/auth&lt;/code&gt; folder called &lt;code&gt;ProfilePage.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Again, you’ll need to wrap the component in the &lt;code&gt;withAuth&lt;/code&gt; component to get that &lt;code&gt;auth&lt;/code&gt; object passed in the props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Link } from 'react-router-dom';
import { withAuth } from '@okta/okta-react';

export default withAuth(class ProfilePage extends React.Component {
  constructor(props){
    super(props);
    this.state = { 
      user: null
    };
    this.getCurrentUser = this.getCurrentUser.bind(this);
  }

  async getCurrentUser(){
    this.props.auth.getUser()
      .then(user =&amp;gt; this.setState({user}));
  }

  componentDidMount(){
    this.getCurrentUser();
  }

  render() {
    if(!this.state.user) return null;
    return (
      &amp;lt;section className="user-profile"&amp;gt;
        &amp;lt;h1&amp;gt;{this.state.user.name}'s Submitted Sessions&amp;lt;/h1&amp;gt;
      &amp;lt;/section&amp;gt;
    )
  }
});

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

&lt;/div&gt;



&lt;p&gt;Simple, right? Just a user object in the state that you can use in the component courtesy of the higher-order component &lt;code&gt;withAuth&lt;/code&gt;! The &lt;code&gt;componentDidMount&lt;/code&gt; lifecycle method retrieves the user, and the &lt;code&gt;render()&lt;/code&gt; method merely checks for it before rendering the page. This allows the component to render while it is waiting for this asynchronous call to come back and update when the user object is there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Routes for the Login and Registration Pages
&lt;/h2&gt;

&lt;p&gt;here are a few things to add in the &lt;code&gt;/ClientApp/boot.js&lt;/code&gt; file. First, you’ll need to import a few things from the Okta React SDK, so add this import statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Security, SecureRoute, ImplicitCallback } from '@okta/okta-react';

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

&lt;/div&gt;



&lt;p&gt;I’ll explain these in a moment when you add them to the &lt;code&gt;render()&lt;/code&gt; method, but for now, you’ll also need to import the components you just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import config from './app.config';
import RegisterPage from './components/auth/RegisterPage';
import ProfilePage from './components/auth/ProfilePage';
import LoginPage from './components/auth/LoginPage';

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

&lt;/div&gt;



&lt;p&gt;Then update the &lt;code&gt;render()&lt;/code&gt; method like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render(
  &amp;lt;BrowserRouter&amp;gt;
    &amp;lt;Security issuer={config.issuer}
      client_id={config.client_id}
      redirect_uri={config.redirect_uri}
      onAuthRequired={onAuthRequired}&amp;gt;
      &amp;lt;Layout&amp;gt;
        &amp;lt;Route exact path="/" component={HomePage} /&amp;gt;
        &amp;lt;Route path="/contact" component={ContactPage} /&amp;gt;
        &amp;lt;Route path="/about" component={AboutPage} /&amp;gt;
        &amp;lt;Route path="/notes" component={NotesPage} /&amp;gt;
        &amp;lt;Route path="/login" render={() =&amp;gt; &amp;lt;LoginPage baseUrl={config.url} /&amp;gt;} /&amp;gt;
        &amp;lt;Route path="/implicit/callback" component={ImplicitCallback} /&amp;gt;
        &amp;lt;Route path="/register" component={RegisterPage} /&amp;gt;
        &amp;lt;SecureRoute path="/profile" component={ProfilePage} /&amp;gt;
      &amp;lt;/Layout&amp;gt;
    &amp;lt;/Security&amp;gt;
  &amp;lt;/BrowserRouter&amp;gt;,
  document.getElementById('app')
);

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

&lt;/div&gt;



&lt;p&gt;There are a couple of things of note here. First, the &lt;code&gt;Security&lt;/code&gt; component. It takes in all your information about your Okta application and wraps all the &lt;code&gt;Route&lt;/code&gt; components so that they can do things like &lt;code&gt;signIn()&lt;/code&gt; and have that information available. It also has an &lt;code&gt;onAuthRequired&lt;/code&gt; property that will be handled by a method you’ll add above the &lt;code&gt;render()&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const onAuthRequired = ({ history }) =&amp;gt; history.push('/login');

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

&lt;/div&gt;



&lt;p&gt;This method redirects the user to the login page when authentication is required (like for the &lt;code&gt;SecureRoute&lt;/code&gt; routes). The &lt;code&gt;SecureRoute&lt;/code&gt; simply fires that &lt;code&gt;onAuthRequired()&lt;/code&gt; handler.&lt;/p&gt;

&lt;p&gt;The login route looks a little funny. There’s no &lt;code&gt;component&lt;/code&gt; property to let React know what component will be handling that route. However, the &lt;code&gt;render&lt;/code&gt; property allows you to specify a “quick component”, if you will, with just a render method. This render method outputs the &lt;code&gt;LoginPage&lt;/code&gt; component, but it passes a &lt;code&gt;baseUrl&lt;/code&gt; property to the props in the component.&lt;/p&gt;

&lt;p&gt;Lastly, the route for &lt;code&gt;/implicit/callback&lt;/code&gt; is handled by the &lt;code&gt;ImplicitCallback&lt;/code&gt; component from Okta’s React SDK. Remember setting that up when you configured your application in Okta? This handles getting the authentication responses back from Okta and storing the user’s tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Navigation to Your React Application
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;/ClientApp/components/common/Navigation.js&lt;/code&gt; file, you’ll need to add navigation links to all these new routes. You’ll want to import that &lt;code&gt;withAuth&lt;/code&gt; component again, wrap the component in the &lt;code&gt;withAuth&lt;/code&gt; higher-order component, and add the methods you’ll need to change the menu items based on whether or not the user is currently logged in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { Link } from 'react-router-dom';
import { withAuth } from '@okta/okta-react';

export default withAuth(class Navigation extends React.Component {
  constructor(props) {
    super(props);
    this.state = { authenticated: null };
    this.checkAuthentication = this.checkAuthentication.bind(this);
    this.logout = this.logout.bind(this);
    this.checkAuthentication();
  }

  async checkAuthentication() {
    const authenticated = await this.props.auth.isAuthenticated();
    if (authenticated !== this.state.authenticated) {
      this.setState({ authenticated });
    }
  }

  componentDidUpdate() {
    this.checkAuthentication();
  }

  logout(){
    this.props.auth.logout('/');
  }

  render() {
    if (this.state.authenticated === null) return null;
    const authNav = this.state.authenticated ?
      &amp;lt;ul className="nav navbar-nav navbar-right"&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href="javascript:void(0)" onClick={this.logout}&amp;gt;Logout&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;Link to="/profile"&amp;gt;Profile&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt; :
      &amp;lt;ul className="nav navbar-nav navbar-right"&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;Link to="/login"&amp;gt;Login&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;Link to="/register"&amp;gt;Register&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;;

    return (
      &amp;lt;div className="navbar navbar-inverse navbar-fixed-top"&amp;gt;
        &amp;lt;div className="container"&amp;gt;
          &amp;lt;div className="navbar-header"&amp;gt;
            &amp;lt;button type="button" className="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"&amp;gt;
              &amp;lt;span className="sr-only"&amp;gt;Toggle navigation&amp;lt;/span&amp;gt;
              &amp;lt;span className="icon-bar"&amp;gt;&amp;lt;/span&amp;gt;
              &amp;lt;span className="icon-bar"&amp;gt;&amp;lt;/span&amp;gt;
              &amp;lt;span className="icon-bar"&amp;gt;&amp;lt;/span&amp;gt;
            &amp;lt;/button&amp;gt;
            &amp;lt;Link to="/" className="navbar-brand"&amp;gt;React App&amp;lt;/Link&amp;gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;div className="navbar-collapse collapse"&amp;gt;
            &amp;lt;ul className="nav navbar-nav"&amp;gt;
              &amp;lt;li&amp;gt;&amp;lt;Link to="/about"&amp;gt;About&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
              &amp;lt;li&amp;gt;&amp;lt;Link to="/contact"&amp;gt;Contact&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
              &amp;lt;li&amp;gt;&amp;lt;Link to="/notes"&amp;gt;Notes&amp;lt;/Link&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
            {authNav}
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    )
  }
})

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

&lt;/div&gt;



&lt;p&gt;The only thing &lt;em&gt;new&lt;/em&gt; here is the ternary operation inside the &lt;code&gt;render()&lt;/code&gt; method. It simply makes some JSX menus based on whether or not the user is authenticated, and stores it in a variable. Then in the &lt;code&gt;return&lt;/code&gt;, it adds that variable as the second, right-side menu.&lt;/p&gt;

&lt;p&gt;With that, you should be able to run the application with &lt;strong&gt;F5&lt;/strong&gt; , register a user, and log them in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a Talk Submission React Component
&lt;/h2&gt;

&lt;p&gt;Now that potential speakers can log in, they’ll need a way to submit proposals to speak at the conference. To do that, create a new group of components by adding a folder in the &lt;code&gt;/ClientApp/components&lt;/code&gt; folder called &lt;code&gt;sessions&lt;/code&gt;. In that folder, create a &lt;code&gt;SubmissionPage.js&lt;/code&gt;. This will handle the creation of proposals and then sending them to the API to be saved in the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { withRouter } from 'react-router-dom';
import { withAuth } from '@okta/okta-react';

class SubmissionPage extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      title: '',
      abstract: '',
      submitted: false
    };

    this.handleTitleChange = this.handleTitleChange.bind(this);
    this.handleAbstractChange = this.handleAbstractChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleTitleChange(e) {
    this.setState({ title: e.target.value });
  }

  handleAbstractChange(e) {
    this.setState({ abstract: e.target.value });
  }

  async handleSubmit(e){
    e.preventDefault();
    fetch('/api/sessions', {
      body: JSON.stringify(this.state),
      cache: 'no-cache',
      headers: {
        'content-type':'application/json',
        Authorization: 'Bearer ' + await this.props.auth.getAccessToken()
      },
      method: 'POST'
    })
    .then(rsp =&amp;gt; {
      if(rsp.status === 201){
        this.props.history.push('/profile');
      }
    })
    .catch(err =&amp;gt; {
      console.error(err);
    });
  }

  render(){
    if(this.state.submitted === true){
      &amp;lt;Redirect to="/profile"/&amp;gt;
    }
    return(
      &amp;lt;form onSubmit={this.handleSubmit}&amp;gt;
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Title:&amp;lt;/label&amp;gt;
          &amp;lt;input
            id="title" type="text"
            value={this.state.title}
            onChange={this.handleTitleChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-element"&amp;gt;
          &amp;lt;label&amp;gt;Abstract:&amp;lt;/label&amp;gt;
          &amp;lt;textarea
            id="abstract"
            cols="100"
            rows="10"
            value={this.state.abstract}
            onChange={this.handleAbstractChange} /&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div className="form-actions"&amp;gt;
          &amp;lt;input id="submit" type="submit" value="Submit Session"/&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/form&amp;gt;
    );
  }

};

export default withAuth(withRouter(SubmissionPage));

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

&lt;/div&gt;



&lt;p&gt;You’ll see this looks quite a bit like the login and registration pages, with some minor differences. The handlers should be very familiar by now for handling field updates and form submission. The significant difference is in the &lt;code&gt;handleSubmit()&lt;/code&gt; function and with the higher-order components.&lt;/p&gt;

&lt;p&gt;The form submission is doing a POST (like the registration page), but it is adding the &lt;code&gt;Authorization&lt;/code&gt; header with a value of “Bearer {theUsersAccessToken}”. This is the reason for using the &lt;code&gt;withAuth&lt;/code&gt; higher-order component, and it is there so that the server side will know who is making the request by sending a &lt;a href="https://oauth.net/2/bearer-tokens/" rel="noopener noreferrer"&gt;Bearer Token&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The form submission handler also uses &lt;code&gt;this.props.history&lt;/code&gt; to redirect the user to back to the profile page once the submission is saved. You’ll also notice that the higher-order functions are also wrapping the submission page component at the bottom. What’s up with that? When using two wrapping function like the use of the &lt;code&gt;withAuth&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; the &lt;code&gt;withRouter&lt;/code&gt; higher-order components, I think it is more readable to export the component at the bottom. Either syntax for exporting components works.&lt;/p&gt;

&lt;p&gt;To make submission easier, add a button on the user’s profile to add a new submission, so that the &lt;code&gt;render()&lt;/code&gt; method looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render() {
  if(!this.state.user) return null;
  return (
    &amp;lt;section className="user-profile"&amp;gt;
      &amp;lt;h1&amp;gt;{this.state.user.name}'s Submitted Sessions&amp;lt;/h1&amp;gt;
      &amp;lt;Link to="/submission" className="btn btn-primary"&amp;gt;Submit A Session&amp;lt;/Link&amp;gt;
    &amp;lt;/section&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;p&gt;Don’t forget to add a secure route to the new component in &lt;code&gt;boot.js&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;SecureRoute path="/submission" component={SubmissionPage} /&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;The submission page will send the user’s input to the server, and now you need to tell the server what to do with all this awesomeness!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Session Creation Route to ASP.NET Core
&lt;/h2&gt;

&lt;p&gt;To save information, you’ll need a couple of things: you’ll need Entity Framework for easier interactions with the data store, and you’ll need a database context for that. In the &lt;code&gt;Models&lt;/code&gt; folder create a &lt;code&gt;ApiContext.cs&lt;/code&gt; file. This C# class should derive from &lt;code&gt;DbContext&lt;/code&gt; and you’ll need to import a using for EntityFramework for that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using Microsoft.EntityFrameworkCore;

namespace okta_dotnetcore_react_example.Data
{
  public class ApiContext : DbContext
  {
    public ApiContext(DbContextOptions&amp;lt;ApiContext&amp;gt; options)
  : base(options)
    { }

    public DbSet&amp;lt;Session&amp;gt; Sessions { get; set; }
  }
}

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

&lt;/div&gt;



&lt;p&gt;This merely sets up a “Sessions” table in the data store where every object of type &lt;code&gt;Session&lt;/code&gt; will be stored.&lt;/p&gt;

&lt;p&gt;You’ll also need a &lt;code&gt;Session&lt;/code&gt; model, so you’ll need to create the &lt;code&gt;Session.cs&lt;/code&gt; file in the &lt;code&gt;Models&lt;/code&gt; folder and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.ComponentModel.DataAnnotations;

namespace okta_dotnetcore_react_example.Models
{
    public class Session
    {
        [Key]
        public int SessionId { get; set; }

        public string UserId { get; set; }
        public string Title { get; set; }
        public string Abstract { get; set; }
    }
}

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

&lt;/div&gt;



&lt;p&gt;The only real thing of note here is the &lt;code&gt;Key&lt;/code&gt; data annotation that tells Entity Framework what the primary key value will be in the table. It also means that since we didn’t specify a way to make a key value, Entity Framework will use the default of incrementing from 1.&lt;/p&gt;

&lt;p&gt;The last database context setup step is to add to the &lt;code&gt;Startup.cs&lt;/code&gt; file in the &lt;code&gt;ConfigureServices()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddDbContext&amp;lt;ApiContext&amp;gt;(options =&amp;gt; options.UseInMemoryDatabase("ConferenceDb"));

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

&lt;/div&gt;



&lt;p&gt;This lets .NET know to inject the database context into every controller that needs it.&lt;/p&gt;

&lt;p&gt;Now you need an endpoint for the React app to send data to. You already know what the endpoint needs to look like, because the submission component is posting data to &lt;code&gt;/api/session&lt;/code&gt;, so you’ll need a controller to handle the incoming data.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Controllers&lt;/code&gt; folder create a file called &lt;code&gt;SessionsController.cs&lt;/code&gt; and add the content as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.Linq;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using okta_dotnetcore_react_example.Data;
using okta_dotnetcore_react_example.Models;

namespace okta_dotnetcore_react_example.Controllers
{
  [Authorize]
  [Route("/api/[controller]")]
  public class SessionsController : Controller
  {
    private readonly ApiContext context;
    public SessionsController(ApiContext context)
    {
      this.context = context;
    }

    [HttpPost]
    public IActionResult AddSession([FromBody] Session session)
    {
      session.UserId = User.Claims.SingleOrDefault(u=&amp;gt;u.Type == "uid")?.Value;
      context.Add&amp;lt;Session&amp;gt;(session);
      context.SaveChanges();
      return Created($"api/sessions/{session.SessionId}", session);
    }
  }
}

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;AddSession&lt;/code&gt; action on the controller has the &lt;code&gt;FromBody&lt;/code&gt; attribute on the argument. This lets ASP.NET’s default model binder know how to take the incoming JSON data and map it to a &lt;code&gt;Session&lt;/code&gt; type. The action then takes the session and sets the &lt;code&gt;UserId&lt;/code&gt; property to the authenticated user’s user id value. Then it adds the session to the &lt;code&gt;Sessions&lt;/code&gt; collection in the context and saves those changes back to the database.&lt;/p&gt;

&lt;p&gt;Lastly, it returns an &lt;code&gt;IActionResult&lt;/code&gt; type. There are some “helpers” that create common action results. Here, it is returning a message with a 201 HTTP status that means there was a resource created. The first argument is the URL to retrieve that resource in the future and the second is the session. The outgoing session will now have a &lt;code&gt;SessionId&lt;/code&gt; that data store created when it inserted the record.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Authorize&lt;/code&gt; attribute on the controller class secures every action on the controller. So to call any endpoint declared here, a user must provide an access token (as a Bearer Token). To ensure that it’s there, you’ll need to add one more thing to the &lt;code&gt;Startup.cs&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;ConfigureServices()&lt;/code&gt; method before the &lt;code&gt;services.AddMvc()&lt;/code&gt; line, add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services.AddAuthentication(sharedOptions =&amp;gt;
{
  sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =&amp;gt;
{
  options.Authority = "https://{yourOktaOrgUrl}/oauth2/default";
  options.Audience = "api://default";
});

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

&lt;/div&gt;



&lt;p&gt;And in the &lt;code&gt;Configure()&lt;/code&gt; method before the &lt;code&gt;app.UseMvc()&lt;/code&gt; line add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.UseAuthentication();

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

&lt;/div&gt;



&lt;p&gt;That’s it! Now your ASP.NET Core app will take that bearer token, get the user’s information from Okta add them to the &lt;code&gt;User&lt;/code&gt; object so you can get the currently requesting user’s data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read The Sessions in You React Application
&lt;/h2&gt;

&lt;p&gt;Even though users can now submit sessions to your conference, they’ll need to be able to see the list of their submissions so that they can see what they’ve submitted, edit, and delete them if they need to. Start by adding the submission listing to the profile page. In the &lt;code&gt;/ClientApp/components/auth/ProfilePage.js&lt;/code&gt; component, add a component for listing a user’s submitted sessions. Change the render method to read:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render() {
  if(!this.state.user) return null;
  return (
    &amp;lt;section className="user-profile"&amp;gt;
      &amp;lt;h1&amp;gt;{this.state.user.name}'s Submitted Sessions&amp;lt;/h1&amp;gt;
      &amp;lt;Link to="/submission" className="btn btn-primary"&amp;gt;Submit A Session&amp;lt;/Link&amp;gt;
      &amp;lt;SessionListing userId={this.state.user.sub} /&amp;gt;
    &amp;lt;/section&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;p&gt;This will pass the currently logged in user’s id to the &lt;code&gt;SessionListing&lt;/code&gt; component you’ll create next.&lt;/p&gt;

&lt;p&gt;Back in the &lt;code&gt;/ClientApp/components/sessions&lt;/code&gt; folder create a &lt;code&gt;SessionListing.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import { withAuth } from '@okta/okta-react';

import './SessionListing.css';
import Session from './Session';

export default withAuth(class SessionListing extends React.Component {
  constructor(props) {
    super(props);
    this.state = { sessions: [] }
  }

  async getUsersSessions() {
    fetch('/api/sessions', {
      headers: {
        Authorization: 'Bearer ' + await this.props.auth.getAccessToken()
      }
    })
    .then(rsp =&amp;gt; rsp.json())
    .then(sessions =&amp;gt; {
      this.setState({ sessions });
    })
    .catch(err =&amp;gt; {
      console.error(err);
    });
  }

  componentDidMount() {
    this.getUsersSessions();
  }

  render() {
    return (
      &amp;lt;ul className="session-list"&amp;gt;
        {this.state.sessions.map(session =&amp;gt; 
          &amp;lt;Session key={session.sessionId} 
            id={session.sessionId} 
            session={session} /&amp;gt;)}
      &amp;lt;/ul&amp;gt;
    )
  }

})

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

&lt;/div&gt;



&lt;p&gt;All of this should be familiar by now. The &lt;code&gt;getUserSessions()&lt;/code&gt; method is called once the component is mounted, and the current user’s access token is sent in the &lt;code&gt;Authorize&lt;/code&gt; header. The &lt;code&gt;map&lt;/code&gt; function being called on the header will essentially loop through the sessions and pass them to the &lt;code&gt;Session&lt;/code&gt; component for display. The &lt;code&gt;render()&lt;/code&gt; method just needs one more thing: a &lt;code&gt;Session&lt;/code&gt; component to pass each session to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hint: If you get a &lt;code&gt;cannot call map on undefined&lt;/code&gt; error. Make sure you’ve initialized your &lt;code&gt;sessions&lt;/code&gt; property in the state to an empty array.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add a &lt;code&gt;Session.js&lt;/code&gt; file to the &lt;code&gt;sessions&lt;/code&gt; folder where your listing component lives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {Link} from 'react-router-dom';

const Session = (props) =&amp;gt; {
  return (
    &amp;lt;li key={props.id} className="session"&amp;gt;
      &amp;lt;h2&amp;gt;{props.session.title}&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;{props.session.abstract}&amp;lt;/div&amp;gt;
    &amp;lt;/li&amp;gt;
  );    
}

export default Session;

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

&lt;/div&gt;



&lt;p&gt;If you’re new to React, this is what is known as a presentational or a “dumb” component. It is not wrapped in the &lt;code&gt;class&lt;/code&gt; type and just takes props and renders output. It is made for this kind of situation. All this component does is display the title and abstract of a session submission.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Sessions from Your ASP.NET Core Application
&lt;/h2&gt;

&lt;p&gt;Now that the React app can request a list of all a user’s sessions, the ASP.NET Core API needs a way to respond. In the &lt;code&gt;SessionsController.cs&lt;/code&gt; file add a new action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpGet]
public IActionResult GetAllSessions()
{
  var userId = User.Claims.SingleOrDefault(u=&amp;gt;u.Type == "uid")?.Value;
  var sessions = context.Sessions.Where(x=&amp;gt;x.UserId == userId).ToList(); 
  return Ok(sessions);
}

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

&lt;/div&gt;



&lt;p&gt;Since this is inside a controller that has the &lt;code&gt;Authorize&lt;/code&gt; attribute on it, there will be a &lt;code&gt;User&lt;/code&gt; object to interrogate. Here, the user returns their “uid”, which is their user’s unique identifier. Then the context searches all the sessions in the data store for the ones belonging to that user and returns them in a 200 OK HTTP status.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the Sessions Editable in React
&lt;/h2&gt;

&lt;p&gt;Now that the users can see their submitted sessions, they’ll need to be able to edit them if they’ve made any mistakes, or want to update the content. To the &lt;code&gt;Session&lt;/code&gt; component change the return so that it reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  return (
    &amp;lt;li key={props.id} className="session"&amp;gt;
      &amp;lt;h2&amp;gt;&amp;lt;Link to={`/submission/${props.session.sessionId}`}&amp;gt;{props.session.title}&amp;lt;/Link&amp;gt;&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;{props.session.abstract}&amp;lt;/div&amp;gt;
    &amp;lt;/li&amp;gt;
  );

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

&lt;/div&gt;



&lt;p&gt;That link will take the user to the submission page and pass the session’s &lt;code&gt;sessionId&lt;/code&gt;. To handle that, you’ll need to update the route for the submission page to handle route parameters. Update the &lt;code&gt;boot.js&lt;/code&gt; file and change the route for &lt;code&gt;/submissions&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;SecureRoute path="/submission/:sessionId?" component={SubmissionPage} /&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;The colon after &lt;code&gt;/submission/&lt;/code&gt; lets React know that the value there will be put into &lt;code&gt;this.props.match.params&lt;/code&gt; for use in the component handling the route. The question mark after the route lets know that the parameter is optional and that the &lt;code&gt;SubmissionPage&lt;/code&gt; component will be handling routes that do and do not have the optional parameter. If the value is not passed the value in &lt;code&gt;this.props.match.params.sessionId&lt;/code&gt; will be undefined.&lt;/p&gt;

&lt;p&gt;Now the submission page just needs to handle loading up an existing session submission. Add a function to the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async loadSubmission(){
  fetch(`/api/sessions/${this.props.match.params.sessionId}`, {
    headers: {
      Authorization: 'Bearer ' + await this.props.auth.getAccessToken()
    }
  })
  .then(rsp =&amp;gt; rsp.json())
  .then(session =&amp;gt; {
    this.setState(Object.assign({}, this.state, session));
  })
  .catch(err =&amp;gt; {
    console.error(err);
  });
}

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

&lt;/div&gt;



&lt;p&gt;Make sure that it is bound to the component’s &lt;code&gt;this&lt;/code&gt; context in the constructor by adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.loadSubmission = this.loadSubmission.bind(this);

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

&lt;/div&gt;



&lt;p&gt;Then make sure the &lt;code&gt;loadSessions()&lt;/code&gt; method only runs once the component has finished rendering by adding the lifecycle method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;componentDidMount(){
  if(this.props.match.params.sessionId){
    this.loadSubmission();
  }
}

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

&lt;/div&gt;



&lt;p&gt;Finally, change the &lt;code&gt;handleSubmit()&lt;/code&gt; method so that it POSTs to the add &lt;strong&gt;or&lt;/strong&gt; save URL in the API depending on whether the user is updating or creating a session. You can determine that based on whether or not a &lt;code&gt;sessionId&lt;/code&gt; was passed as a route parameter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async handleSubmit(e){
  e.preventDefault();
  var sessionId = this.props.match.params.sessionId;
  var url = sessionId ? `/api/sessions/${sessionId}` : '/api/sessions';
  fetch(url, {
    body: JSON.stringify(this.state),
    cache: 'no-cache',
    headers: {
      'content-type':'application/json',
      Authorization: 'Bearer ' + await this.props.auth.getAccessToken()
    },
    method: 'POST'
  })
  .then(rsp =&amp;gt; {
    if(rsp.status === 201 || rsp.status === 200){
      this.props.history.push('/profile');
    }
  })
  .catch(err =&amp;gt; {
    console.error(err);
  });
}

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

&lt;/div&gt;



&lt;p&gt;This pulls the &lt;code&gt;sessionId&lt;/code&gt; out and if it exists, changes the URL where you are posting the session data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update a Session in ASP.NET Core API
&lt;/h2&gt;

&lt;p&gt;Now that the infrastructure is in place for the data store and the authentication, adding to the API is very simple. To the &lt;code&gt;SessionsController.cs&lt;/code&gt; add the following action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpPost("/api/sessions/{sessionId}")]
public IActionResult UpdateSession([FromBody] Session session)
{
  var savedSession = context.Sessions.SingleOrDefault(x=&amp;gt;x.SessionId == session.SessionId);
  if(savedSession == null){
    return NotFound();
  }
  if(savedSession.UserId != User.Claims.SingleOrDefault(u=&amp;gt;u.Type == "uid")?.Value)
  {
    return Unauthorized();
  }
  savedSession.Title = session.Title;
  savedSession.Abstract = session.Abstract;
  context.SaveChanges();
  return Ok(savedSession);
}

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

&lt;/div&gt;



&lt;p&gt;This action has a specified URL in the &lt;code&gt;HttpPost&lt;/code&gt; attribute. Just like the action for creating sessions, this pulls the data from the JSON data and maps it to a session object. Unlike the create action, this looks up the session by its &lt;code&gt;sessionId&lt;/code&gt;. If it doesn’t find one, it returns a &lt;code&gt;NotFound&lt;/code&gt; action result.&lt;/p&gt;

&lt;p&gt;The action then checks to see if the currently logged in user is the owner of that session by checking their ID against the session’s &lt;code&gt;UserId&lt;/code&gt; property. If it doesn’t match, it returns an &lt;code&gt;Unauthorized&lt;/code&gt; action result.&lt;/p&gt;

&lt;p&gt;Once all those checks have passed, the session is updated with the incoming data and saved back to the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete Submissions From React
&lt;/h2&gt;

&lt;p&gt;Lastly, a potential speaker might decide that they don’t want to submit that session for consideration after all. They will need a way to delete that session submission.&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;deleteSession()&lt;/code&gt; method to the session listing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async deleteSession(session){
  fetch(`/api/sessions/${session.sessionId}`, {
    method: 'DELETE',
    headers: {
      Authorization: 'Bearer ' + await this.props.auth.getAccessToken()
    }
  })
  .then(rsp =&amp;gt; {
    if(rsp.status === 200){
      this.getUsersSessions();
    }
  })
  .catch(err =&amp;gt; {
    console.error(err);
  });
}

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

&lt;/div&gt;



&lt;p&gt;As before, you are sending the user’s access token. This time to a &lt;code&gt;DELETE&lt;/code&gt; endpoint. The reason this is here and not in the session component is so that the list will be redisplayed once the submission has been deleted. To call it from the session component, you’ll need to pass it as an action.&lt;/p&gt;

&lt;p&gt;You also won’t want to even give the option to someone who doesn’t own that session, so first check the &lt;code&gt;userId&lt;/code&gt; passed in the props against the session’s &lt;code&gt;userId&lt;/code&gt; property. In the &lt;code&gt;SessionListing.js&lt;/code&gt; component, change the &lt;code&gt;render()&lt;/code&gt; method, so it reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;render() {
  return (
    &amp;lt;ul className="session-list"&amp;gt;
      {this.state.sessions.map(session =&amp;gt; 
        &amp;lt;Session key={session.sessionId} 
          id={session.sessionId}
          isOwner={session.userId === this.props.userId}
          delete={this.deleteSession.bind(this, session)} 
          session={session} /&amp;gt;)}
    &amp;lt;/ul&amp;gt;
  )
}

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

&lt;/div&gt;



&lt;p&gt;Now you can edit the &lt;code&gt;Session.js&lt;/code&gt; file. The final version of the file will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {Link} from 'react-router-dom';

const Session = (props) =&amp;gt; {
  const deleteButton = props.isOwner ? 
    &amp;lt;input type="button" title="Delete This Session" className="btn btn-sm btn-danger" value="X" onClick={props.delete}/&amp;gt; : 
    null;
  return (
    &amp;lt;li key={props.id} className="session"&amp;gt;
      &amp;lt;h2&amp;gt;&amp;lt;Link to={`/submission/${props.session.sessionId}`}&amp;gt;{props.session.title}&amp;lt;/Link&amp;gt; {deleteButton}&amp;lt;/h2&amp;gt;
      &amp;lt;div&amp;gt;{props.session.abstract}} /&amp;gt;
    &amp;lt;/li&amp;gt;
  );    
}

export default Session;

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

&lt;/div&gt;



&lt;p&gt;Now the component uses the &lt;code&gt;isOwner&lt;/code&gt; prop to decide whether or not to show the delete button, and the delete button calls the &lt;code&gt;delete()&lt;/code&gt; method on the session listing component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delete Sessions in ASP.NET Core
&lt;/h2&gt;

&lt;p&gt;Now that the React application can request a delete to a specific session, add the action to handle that request in the &lt;code&gt;SessionsController.cs&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[HttpDelete("/api/sessions/{sessionId}")]
public IActionResult Delete(int sessionId){
  var session = context.Sessions.SingleOrDefault(sess =&amp;gt; sess.SessionId == sessionId);
  if(session == null){
    return NotFound();
  }
  if(session.UserId != User.Claims.SingleOrDefault(u=&amp;gt;u.Type == "uid")?.Value)
  {
    return Unauthorized();
  }
  context.Remove(session);
  context.SaveChanges();
  return Ok();
}

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

&lt;/div&gt;



&lt;p&gt;Just like the update action, you’ll want to make sure that the session that the request intends to delete exists, and that it belongs to the user making the request. If that is the case, then the &lt;code&gt;Remove()&lt;/code&gt; method is called on the context, and the session to be deleted is passed to it. Finally, don’t forget to call &lt;code&gt;SaveChanges()&lt;/code&gt; to write that context back to the database and return an &lt;code&gt;Ok()&lt;/code&gt; action result.&lt;/p&gt;

&lt;p&gt;You should now be able to run the app and register users, login, create, read, update, and delete session submissions!&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%2Fcrud-aspnet-core-react%2Fcrud-app-running-998e5cea339f4253282658c669b1b34c805b2378fa39178eedb2cd7dbef93276.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%2Fcrud-aspnet-core-react%2Fcrud-app-running-998e5cea339f4253282658c669b1b34c805b2378fa39178eedb2cd7dbef93276.png" alt="Application Running Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Do More Full Stack!!
&lt;/h2&gt;

&lt;p&gt;If you enjoyed building this ASP.NET Core API with React, check out more full-stack CRUD posts from Okta.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/02/15/build-crud-app-vuejs-node" rel="noopener noreferrer"&gt;Build a Basic CRUD App with Vue.js and Node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/06/14/php-crud-app-symfony-vue" rel="noopener noreferrer"&gt;Build a Basic CRUD App with Symfony 4 and Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.okta.com/blog/2018/04/26/build-crud-app-aspnetcore-angular" rel="noopener noreferrer"&gt;Build a CRUD App with ASP.NET Core and Angular&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always if you have any questions, comments, or concerns about this post feel free to leave a comment below. For other great content from the Okta Dev Team, follow us on Twitter &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;@OktaDev&lt;/a&gt;, &lt;a href="https://www.facebook.com/oktadevelopers/" rel="noopener noreferrer"&gt;Facebook&lt;/a&gt;, and watch us on &lt;a href="https://www.youtube.com/channel/UC5AMiWqFVFxF1q9Ya1FuZ_Q" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>react</category>
      <category>security</category>
    </item>
    <item>
      <title>Add Auth to Your PWA with Okta and Stencil</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Tue, 12 Jun 2018 00:55:42 +0000</pubDate>
      <link>https://forem.com/oktadev/add-auth-to-your-pwa-with-okta-and-stencil-1lam</link>
      <guid>https://forem.com/oktadev/add-auth-to-your-pwa-with-okta-and-stencil-1lam</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/blog/2017/07/20/the-ultimate-guide-to-progressive-web-applications"&gt;Progressive Web Applications&lt;/a&gt; (PWAs) are the newest technology on the web dev block and they’ve arrived just in time to solve a growing problem. Many companies are struggling to keep isolated development teams across their organization up-to-date when new features are released. Some companies are even trying to decide if it's worth the cost to develop both a web app &lt;em&gt;and&lt;/em&gt; a mobile application. Not surprisingly, it's a headache most companies are looking to avoid. PWAs can give companies a lot of the features they need from a mobile app without the need to manage multiple teams and codebases.&lt;/p&gt;

&lt;p&gt;A &lt;a href="https://developers.google.com/web/progressive-web-apps/" rel="noopener noreferrer"&gt;PWA&lt;/a&gt; performs spectacularly when on a fast connection and still performs well when offline or on Wi-Fi that's not really fast enough to be called Wi-Fi (sometimes called "Lie-Fi"). It does so via caching and a JavaScript "Service Worker" that intercepts server calls and tries to serve the data from cache first, then when the server finally responds, it will replace the cached data with possibly "fresher" data from the server.&lt;/p&gt;

&lt;p&gt;Recently, the &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic&lt;/a&gt; team released a new project called &lt;a href="https://stenciljs.com/" rel="noopener noreferrer"&gt;Stencil&lt;/a&gt;. Stencil is a compiler that generates standards-compliant web components. Unlike most JavaScript frameworks, it doesn't deliver a "framework" of code to the browser. It simply takes the code you write and uses its compiler to create vanilla components. You can also use Stencil's compiler &lt;em&gt;with&lt;/em&gt; your favorite framework. The &lt;a href="https://github.com/ionic-team/stencil-app-starter" rel="noopener noreferrer"&gt;Stencil starter project&lt;/a&gt; is the easiest way to get started with Stencil and produces a base application that scores nearly a 100% score on &lt;a href="https://developers.google.com/web/tools/lighthouse/" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt;'s progressive web app scorecard.&lt;/p&gt;

&lt;p&gt;To get started building a PWA using Stencil, clone the starter application and detach it from the GitHub remote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: Stencil is not at a 1.0 release yet (as of this writing). So be aware that if you continue, you're in early-adopter territory. If you find bugs, &lt;a href="https://github.com/ionic-team/stencil/issues" rel="noopener noreferrer"&gt;submit an issue&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up the Starter Application
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/ionic-team/stencil-starter.git first-stencil
&lt;span class="nb"&gt;cd &lt;/span&gt;first-stencil
git remote &lt;span class="nb"&gt;rm &lt;/span&gt;origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, install all the dependencies that your new Stencil app will need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may see a couple of warnings from &lt;code&gt;node-pre-gyp&lt;/code&gt; around &lt;code&gt;fsevents&lt;/code&gt;. There's nothing to see here. This is just to get around a &lt;a href="https://github.com/strongloop/fsevents/issues/157" rel="noopener noreferrer"&gt;nasty little npm bug&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, add the Okta Auth SDK (via CDN) to the bottom of the &lt;code&gt;index.html&lt;/code&gt; page, right before the closing &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ok1static.oktacdn.com/assets/js/sdk/okta-auth-js/1.8.0/okta-auth-js.min.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While there is an npm package for Okta's Auth SDK, Stencil has a hard time compiling it. Overall it works better for now if you just use the CDN to include it.&lt;/p&gt;

&lt;p&gt;If you’re like me, the next thing you’ll want to do is run &lt;code&gt;npm start&lt;/code&gt; and check the site with Lighthouse. If you do, you’ll notice that the score is &lt;em&gt;kind of&lt;/em&gt; low. In particular, it doesn’t register a service worker or return a 200 when offline, That’s because it’s a &lt;em&gt;development&lt;/em&gt; build, and generally, you don’t want the service worker intercepting server calls and returning cached data in development.&lt;/p&gt;

&lt;p&gt;To ensure an accurate depiction of the kind of PWA you get out of the box with Stencil, make sure to run a &lt;em&gt;production&lt;/em&gt; build using &lt;code&gt;npm run build&lt;/code&gt;. Once you do, you’ll see a &lt;code&gt;www&lt;/code&gt; folder and inside that folder, you’ll see a &lt;code&gt;sw.js&lt;/code&gt; file. That’s your service worker!&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Up Your Okta Application
&lt;/h2&gt;

&lt;p&gt;If you haven't already done so, create a free-forever developer account at &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;https://developer.okta.com/signup/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you've registered, click on &lt;strong&gt;Applications&lt;/strong&gt; in the top menu. Then click &lt;strong&gt;Add Application&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fadd-auth-to-stencil%2FApplicationListingScreen-008adbfcd6aba9acfd19054bca9bbd360a1e1d6f58b20ae85aa7532141c65c3f.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%2Fadd-auth-to-stencil%2FApplicationListingScreen-008adbfcd6aba9acfd19054bca9bbd360a1e1d6f58b20ae85aa7532141c65c3f.png" alt="Application Listing Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will then be taken to the application creation wizard. Choose &lt;strong&gt;Single-Page App&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt; at the bottom.&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%2Fadd-auth-to-stencil%2FCreateApplicationScreenSPA-64f2eb2b85fdf060d61b602f1e77fca29f3a07c09a9be1224694b91106581647.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%2Fadd-auth-to-stencil%2FCreateApplicationScreenSPA-64f2eb2b85fdf060d61b602f1e77fca29f3a07c09a9be1224694b91106581647.png" alt="Create Application Screen SPA"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, you’ll see the default settings provided by the single-page application template. Change the name of the application to something more descriptive, like "Stencil SPA". Also, change the base URIs and the login redirect URIs settings to use port 3333 because that’s where your application will be running. The rest of the default settings are fine.&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%2Fadd-auth-to-stencil%2FApplicationSettingStencil-a5ef20862100e81001e35f69cf0c9b7c30155d8f54380e633d33cc1c59ac906b.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%2Fadd-auth-to-stencil%2FApplicationSettingStencil-a5ef20862100e81001e35f69cf0c9b7c30155d8f54380e633d33cc1c59ac906b.png" alt="Application Settings Screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Done&lt;/strong&gt; at the bottom.&lt;/p&gt;

&lt;p&gt;Select your newly created application from the listing, and click on the &lt;strong&gt;General&lt;/strong&gt; tab to view the general settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fadd-auth-to-stencil%2FGeneralSettingsClientId-f23a50d696788bf92c681465762a32e578ef6e52f733809722d47c32f9518dc9.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%2Fadd-auth-to-stencil%2FGeneralSettingsClientId-f23a50d696788bf92c681465762a32e578ef6e52f733809722d47c32f9518dc9.png" alt="General Settings Client Id"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom, you’ll see a &lt;strong&gt;Client ID&lt;/strong&gt; setting (yours won't be blurred out, obviously). Copy this to use in your Stencil application. You will also need your Okta organization URL, which you can find at the top right of the dashboard page. It will probably look something like “&lt;a href="https://dev-XXXXXX.oktapreview.com%E2%80%9D" rel="noopener noreferrer"&gt;https://dev-XXXXXX.oktapreview.com”&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Authentication Component
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;components&lt;/code&gt; folder, add a new folder called &lt;code&gt;app-auth&lt;/code&gt;. This is where your login page component will go. You can call it whatever you want, I'm just following the naming conventions set out by the starter app here. I'd definitely recommend deciding on a naming convention early and sticking with it.&lt;/p&gt;

&lt;p&gt;Inside the newly created &lt;code&gt;app-auth&lt;/code&gt; folder create two files: &lt;code&gt;app-auth.css&lt;/code&gt; and &lt;code&gt;app-auth.tsx&lt;/code&gt;. Start by creating the shell of the &lt;code&gt;app-auth.tsx&lt;/code&gt; file.&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="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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stencil/core&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="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tag&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-auth&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrl&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-auth.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppAuth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&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;If you are like I was, you might be thinking, "What kind of Frankenstein framework is this?"&lt;/p&gt;

&lt;p&gt;You'll notice the &lt;code&gt;@Component&lt;/code&gt; decorator over the &lt;code&gt;AppAuth&lt;/code&gt; class declaration like Angular, and then a &lt;code&gt;render()&lt;/code&gt; method at the bottom like React. To me, that's the beauty of Stencil. It takes some of the best parts of both popular frameworks and uses them to compile reusable components!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a Login Form
&lt;/h2&gt;

&lt;p&gt;Next, you'll add the JSX (that's right, I said it) to the new component. Change the &lt;code&gt;render()&lt;/code&gt; method to:&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;render&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app-auth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;autocomplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-item&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;autocomplete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;current-password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-actions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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="k"&gt;this&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="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Login&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just a regular JSX form, but the login button's &lt;code&gt;onClick&lt;/code&gt; event is currently wired to function that doesn't exist. &lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Login Method's Dependencies
&lt;/h2&gt;

&lt;p&gt;Before you create that function, you'll need to set up the &lt;code&gt;OktaAuth&lt;/code&gt; JavaScript object to call the Okta API for authentication. You'll add the object to the component's state, so right below the class declaration, add the following line:&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="nd"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;authClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will also have to import the &lt;code&gt;@State()&lt;/code&gt; decorator. This is is used for values related to the internal state of the component. In the first &lt;code&gt;import&lt;/code&gt; statement add State to the deconstruction list.&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="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;State&lt;/span&gt; &lt;span class="p"&gt;}&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;@stencil/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need to get the username and password values from the form itself, so add an &lt;code&gt;@Element()&lt;/code&gt; to the code right below that &lt;code&gt;@State()&lt;/code&gt; like you just created, so it read 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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;authClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then also add the &lt;code&gt;@Element()&lt;/code&gt; decorator to the import so it reads:&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="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;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="p"&gt;}&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;@stencil/core&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;One last thing that the &lt;code&gt;login()&lt;/code&gt; function will need is access to the router, so you can redirect the user to their profile page if their authentication is successful. You'll need a class property, so add it right below the &lt;code&gt;@Element&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="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;authClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouterHistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To import it, add the &lt;code&gt;@Prop()&lt;/code&gt; decorator to the main import and then import the &lt;code&gt;RouterHistory&lt;/code&gt; from &lt;code&gt;@stencil/router&lt;/code&gt; right below the core import statement. The &lt;code&gt;@Prop&lt;/code&gt; decorator is used to define properties that can be passed in to your component. In this case, it's not a passed in value, but it could be if need be. Your final import section should read:&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="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;Prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Listen&lt;/span&gt; &lt;span class="p"&gt;}&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;@stencil/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RouterHistory&lt;/span&gt; &lt;span class="p"&gt;}&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;@stencil/router&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;Finally, to use the &lt;code&gt;OktaAuth&lt;/code&gt; JavaScript library you brought in from the CDN, add a declaration for it right below the import statements.&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;declare&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;OktaAuth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add the Login Method
&lt;/h2&gt;

&lt;p&gt;Now you included everything you'll need to get the login function to authenticate users with your Okta organization. First, set up the &lt;code&gt;OktaAuth&lt;/code&gt; object in the constructor of the &lt;code&gt;AppAuth&lt;/code&gt; class. Right below the property for the &lt;code&gt;RouterHistory&lt;/code&gt; object, add:&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;constructor&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;authClient&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;OktaAuth&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;url&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&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;default&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;You can get your Client ID from that general settings page of your Okta 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%2Fadd-auth-to-stencil%2FGeneralSettingsClientId-f23a50d696788bf92c681465762a32e578ef6e52f733809722d47c32f9518dc9.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%2Fadd-auth-to-stencil%2FGeneralSettingsClientId-f23a50d696788bf92c681465762a32e578ef6e52f733809722d47c32f9518dc9.png" alt="General Settings Client Id"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll also need your Okta org URL, from the upper-right side of the Okta dashboard page.&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%2Fadd-auth-to-stencil%2FOktaOrgUrlDashboard-b9283a021008d94d056e5a4ac6d2b130ff00a71e8c4d6a44f7029af95392a8f1.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%2Fadd-auth-to-stencil%2FOktaOrgUrlDashboard-b9283a021008d94d056e5a4ac6d2b130ff00a71e8c4d6a44f7029af95392a8f1.png" alt="Okta Dashboard Org Url"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now everything is set up for the &lt;code&gt;login()&lt;/code&gt; function, so you'll create that next. Right above the &lt;code&gt;render()&lt;/code&gt; method, add a &lt;code&gt;login()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;inputs&lt;/span&gt; &lt;span class="o"&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;host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&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;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;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;value&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="nx"&gt;authClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SUCCESS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWithoutPrompt&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;responseType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;scopes&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;openid&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;profile&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;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="na"&gt;sessionToken&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;sessionToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;redirectUri&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:3333&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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;okta_id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="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;history&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;/profile&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="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="s2"&gt;`Unable to handle &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;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; status code`&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="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since is really the "meat" of the component, I'll walk you through what's going on here.&lt;/p&gt;

&lt;p&gt;The first thing, is getting all the inputs inside the &lt;code&gt;form&lt;/code&gt; element of the component. Then a user object is created with the username and password from their respective inputs.&lt;/p&gt;

&lt;p&gt;Next the &lt;code&gt;authClient&lt;/code&gt; object is used to call the &lt;code&gt;signIn()&lt;/code&gt; method with the user object that was created. It returns a promise, so you handle the &lt;code&gt;then&lt;/code&gt; condition by getting the response and check to see if the response's status is a 200. If it is, call the &lt;code&gt;authClient.token&lt;/code&gt;'s &lt;code&gt;getWithoutPrompt()&lt;/code&gt; method which also returns a promise. It takes a &lt;code&gt;responseType&lt;/code&gt; property which is set to &lt;code&gt;id_token&lt;/code&gt;, because that's what you want to get from Okta. You've also asked for three scopes that will give you the openid, profile, and email data associated with the newly authenticated user. The method need the session token returned from the &lt;code&gt;signIn()&lt;/code&gt; method's response. Finally, you've told the function to call back to the &lt;code&gt;redirectUri&lt;/code&gt;, which was set as a trusted redirect origin in Okta when you created your application.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;then&lt;/code&gt; condition of this promise, you take the id token received and set it in local storage as &lt;code&gt;okta_id_token&lt;/code&gt;. If all that worked, the user is redirected to the profile page.&lt;/p&gt;

&lt;p&gt;If the response had a status of anything other than 200, it merely throws an error that says it can't handle any other statuses. Finally, the fail condition for the &lt;code&gt;signIn()&lt;/code&gt; method call simply logs any errors to the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplify Login
&lt;/h2&gt;

&lt;p&gt;While this works, there are two things that would make this component a little nicer: being able to hit enter to log in instead of having to click the login button, and not even showing the login form if the person tries to go the login page when they're already logged in.&lt;/p&gt;

&lt;p&gt;To achieve this, add a method to take the user directly to the profile page if they're already logged in. Like React components, Stencil components have lifecycle methods. Instead of &lt;code&gt;componentWillMount()&lt;/code&gt; for React, Stencil has a &lt;code&gt;componentWillLoad()&lt;/code&gt; method, so that's what you'll use here.&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;componentWillLoad&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;idToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;okta_id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idToken&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;history&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;/profile&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply put, all you're doing is reading the token from local storage. If one exists, you're assuming they are logged in and redirecting them to the profile page.&lt;/p&gt;

&lt;p&gt;The last thing that will make this login form easier to use is to add the ability to submit the form with the enter key. Stencil has some built-in listeners for key presses. In this case, use the 'keydown.enter' listener. Import the &lt;code&gt;@Listen()&lt;/code&gt; decorator in the very top import statement where you imported &lt;code&gt;Component&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;import&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;Prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Listen&lt;/span&gt; &lt;span class="p"&gt;}&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;@stencil/core&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;Then add a handler for the 'keydown.enter' event just below the &lt;code&gt;componentWillLoad()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown.enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;handleEnter&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;login&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;
  
  
  Update the Profile Page
&lt;/h2&gt;

&lt;p&gt;Now that you have a nice login page, update the profile page so that it shows the user's claims once they're logged in.&lt;/p&gt;

&lt;p&gt;First, you’ll need a type to put the user’s claims in. So create a new file in the &lt;code&gt;app-profile&lt;/code&gt; folder called &lt;code&gt;AppUser.tsx&lt;/code&gt;. The contents are simple, but long. I simply looked at all the claims in the token stored in &lt;code&gt;localStorage&lt;/code&gt; and created an interface that matched it. So the &lt;code&gt;AppUser.tsx&lt;/code&gt; file is as follows:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AppUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;sub&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="nl"&gt;name&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="nl"&gt;locale&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="nl"&gt;email&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="nl"&gt;ver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;iss&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="nl"&gt;aud&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="nl"&gt;iat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;jti&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="nl"&gt;amr&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="nl"&gt;idp&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="nl"&gt;nonce&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="nl"&gt;nickname&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="nl"&gt;preferred_username&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="nl"&gt;given_name&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="nl"&gt;family_name&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="nl"&gt;zoneinfo&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="nl"&gt;updated_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;email_verified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;auth_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&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;Once you have a type to declare for your profile's user object, update the &lt;code&gt;app-profile.tsx&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The imports at the top should look like:&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="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;Prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@stencil/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RouterHistory&lt;/span&gt; &lt;span class="p"&gt;}&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;@stencil/router&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;Remove the &lt;code&gt;@Prop()&lt;/code&gt; line for &lt;code&gt;match&lt;/code&gt; and replace is with:&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="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RouterHistory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppUser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Prop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;isServer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;isServer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;isServer&lt;/code&gt; property is a special property. Because Stencil supports prerendering and &lt;code&gt;localStorage&lt;/code&gt; may not be available during prerender, you'll need to wrap the &lt;code&gt;localStorage&lt;/code&gt; calls in an &lt;code&gt;if(!isServer){}&lt;/code&gt; to make sure it will build for production. This shouldn't stop it from working, it's just a work around for the build process.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;componentWillLoad()&lt;/code&gt; method, just read in the user information from the 'okta_id_token' in local storage:&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;componentWillLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isServer&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;okta_id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&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="nx"&gt;token&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="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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;/login&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will be your protector for the profile page as well, it just checks if the token exists. If so, it loads the claims from it. If not, it redirects to the login page.&lt;/p&gt;

&lt;p&gt;For the &lt;code&gt;render()&lt;/code&gt; method, change it to display the claims in a list.&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;render&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;user&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;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;Claims&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&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;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&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;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt;: {this.user&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;key&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;}&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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;logout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Logout&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing left is to add the &lt;code&gt;logout()&lt;/code&gt; method. This will just remove the token from local storage and reload the page, this will force the &lt;code&gt;componentWillLoad()&lt;/code&gt; to redirect the user to the login page.&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;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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;okta_id_token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reload&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;
  
  
  Set Up the Login Route
&lt;/h2&gt;

&lt;p&gt;The only thing left is to add the route to the login component to the application so that users can get there.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;components/my-app/my-app.tsx&lt;/code&gt; file add the route inside the &lt;code&gt;stencil-router&lt;/code&gt; component so that the final section looks like this:&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;stencil-router&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;stencil-route&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;component=&lt;/span&gt;&lt;span class="s"&gt;"app-home"&lt;/span&gt; &lt;span class="na"&gt;exact=&lt;/span&gt;&lt;span class="s"&gt;{true}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;stencil-route&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt; &lt;span class="na"&gt;component=&lt;/span&gt;&lt;span class="s"&gt;"app-profile"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;stencil-route&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"/login"&lt;/span&gt; &lt;span class="na"&gt;component=&lt;/span&gt;&lt;span class="s"&gt;"app-auth"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/stencil-router&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need to update the route for the link on the home page. In &lt;code&gt;components/app-home/app-home.tsx&lt;/code&gt; update the &lt;code&gt;stencil-route-link&lt;/code&gt; element's url to no longer pass in the url parameter.&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;stencil-route-link&lt;/span&gt; &lt;span class="na"&gt;url=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
    Profile page
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/stencil-route-link&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You should now be able to run the app, click on the profile page, get redirected to the login page, and be redirected back to the profile page once you've logged in. The profile page should show all your claims after you've authenticated.&lt;/p&gt;

&lt;p&gt;Congratulations, you now have a PWA with authentication in it, ready to go conquer the world!&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Styles
&lt;/h2&gt;

&lt;p&gt;As extra credit, you might want to add some styling to the login form and the profile page. Below is my style sheet for the login page that goes in &lt;code&gt;app-auth.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.app-auth&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2rem&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.app-auth&lt;/span&gt; &lt;span class="nc"&gt;.form-item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;.25rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.app-auth&lt;/span&gt; &lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.app-auth&lt;/span&gt; &lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;97%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;.25rem&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="nc"&gt;.app-auth&lt;/span&gt; &lt;span class="nc"&gt;.form-actions&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;right&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;Finally, in &lt;code&gt;app-profile.css&lt;/code&gt; just some simple styles to bold the label of each item.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.app-profile&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.app-profile&lt;/span&gt; &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="nt"&gt;span&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="nb"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you run the app, you will see a nicely styled application, ready for the web!&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%2Fadd-auth-to-stencil%2FStencilAppLoginPage-2790ae37ee773e9a4478da7f266be8908753c6f685a81c3de2618ae76b47d30c.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%2Fadd-auth-to-stencil%2FStencilAppLoginPage-2790ae37ee773e9a4478da7f266be8908753c6f685a81c3de2618ae76b47d30c.png" alt="Stencil App Login Page"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;To learn more about PWAs, check out Matt Raible's &lt;a href="https://dev.to/blog/2017/07/20/the-ultimate-guide-to-progressive-web-applications"&gt;ultimate guide to PWAs&lt;/a&gt; on the Okta developer blog.&lt;/p&gt;

&lt;p&gt;If you want to know more about Ionic apps, check out Matt's blog post about &lt;a href="https://dev.to/blog/2017/08/22/build-an-ionic-app-with-user-authentication"&gt;building Ionic apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can learn about building a basic CRUD app with VueJS from &lt;a href="https://dev.to/blog/2018/02/15/build-crud-app-vuejs-node"&gt;Brandon Parise's post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, right here you can see &lt;a href="https://dev.to/blog/2018/02/06/build-user-registration-with-node-react-and-okta"&gt;how to set up user registration with Node and React&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;As always, if you have any questions you can comment below or  hit me up on Twitter &lt;a href="https://twitter.com/leebrandt" rel="noopener noreferrer"&gt;@leebrandt&lt;/a&gt; and don't forget to follow &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;@OktaDev&lt;/a&gt; for great content from our communities + all the news about Okta's developer platform!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>stencil</category>
      <category>pwa</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Build User Registration with Node, React, and Okta</title>
      <dc:creator>Lee Brandt</dc:creator>
      <pubDate>Tue, 29 May 2018 22:15:40 +0000</pubDate>
      <link>https://forem.com/oktadev/build-user-registration-with-node-react-and-okta-3944</link>
      <guid>https://forem.com/oktadev/build-user-registration-with-node-react-and-okta-3944</guid>
      <description>&lt;p&gt;Today's internet users expect a personalized experience. Developers must learn to develop websites that provide that personalized experience while keeping their user's information private. Modern web applications also tend to have a server-side API and a client-side user interface. it can be challenging to get make both ends aware of the currently logged in user. In this tutorial, I will walk you through setting up a Node API that feeds a React UI, and build a user registration that keeps the user's information private and personal.&lt;/p&gt;

&lt;p&gt;In this tutorial, I won't use any state management libraries like Redux or ReduxThunk. In a more robust application, you'll probably want to do that, but it will be easy to wire up Redux and ReduxThunk and then add the &lt;code&gt;fetch&lt;/code&gt; statements used here as your thunks. For the sake of simplicity, and to keep this article focused on adding user management, I'll be adding fetch statements into &lt;code&gt;componentDidMount&lt;/code&gt; functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Node and React Prerequisites
&lt;/h2&gt;

&lt;p&gt;To set up the base application, make sure you have these basic tools installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node (8+)&lt;/li&gt;
&lt;li&gt;npm (5+)&lt;/li&gt;
&lt;li&gt;create-react-app (npm package)&lt;/li&gt;
&lt;li&gt;express-generator (npm package)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll also need an &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;Okta developer account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install Node and npm, you can follow the instructions for your operating system at &lt;a href="https://nodejs.org/en/" rel="noopener noreferrer"&gt;https://nodejs.org/en/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then just install the two npm packages with the npm command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; create-react-app express-generator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you're ready to set up the basic application structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaffold the Base Application
&lt;/h2&gt;

&lt;p&gt;Go to the folder where you want your application to live and create a new folder for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;MembershipSample
&lt;span class="nb"&gt;cd &lt;/span&gt;MembershipSample
express api
create-react-app client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create two folders in the &lt;code&gt;MembershipSample&lt;/code&gt; folder called &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;client&lt;/code&gt;, with a NodeJS and Express application in the &lt;code&gt;api&lt;/code&gt; folder and a base React application in the &lt;code&gt;client&lt;/code&gt; folder. So your folder structure will look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MembershipSample

&lt;ul&gt;
&lt;li&gt;api&lt;/li&gt;
&lt;li&gt;client&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;To make this next part easier, open two terminals or terminal tabs; one to the express app folder &lt;code&gt;api&lt;/code&gt; and the other to the React app folder &lt;code&gt;client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By default, the React app and the Node app will both run on port 3000 in development, so you'll need to get the API to run on a different port and then proxy it in the client app. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;api&lt;/code&gt; folder, open the &lt;code&gt;/bin/www&lt;/code&gt; file and change the port the API will be running on to &lt;code&gt;3001&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="cm"&gt;/**
 * Get port from environment and store in Express.
 */&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;normalizePort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3001&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;port&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set up the proxy for the API in the client application so that you can still call &lt;code&gt;/api/{resource}&lt;/code&gt; and have it proxied from port 3000 to port 3001. In the &lt;code&gt;client/package.json&lt;/code&gt; file, add the &lt;code&gt;proxy&lt;/code&gt; setting below &lt;code&gt;name&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://localhost:3001&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, don’t forget to run &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;yarn install&lt;/code&gt; for each subfolder (&lt;code&gt;api&lt;/code&gt; and &lt;code&gt;client&lt;/code&gt;) to ensure that the dependencies are installed.&lt;/p&gt;

&lt;p&gt;You can now run both applications by running &lt;code&gt;npm start&lt;/code&gt; or &lt;code&gt;yarn start&lt;/code&gt; in the appropriate folders for the API and the client application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add an Okta Application
&lt;/h2&gt;

&lt;p&gt;If you haven't already done so, create a free forever developer account at &lt;a href="https://developer.okta.com/signup/" rel="noopener noreferrer"&gt;https://developer.okta.com/signup/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you've registered, click on &lt;strong&gt;Applications&lt;/strong&gt; in the top menu. Then click the &lt;strong&gt;Add Application&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fapplication-listing-screen-8bd2b4155458ca8d3380392548a4069b3bd0257cf41739e08c7718d3e2e5fe50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fapplication-listing-screen-8bd2b4155458ca8d3380392548a4069b3bd0257cf41739e08c7718d3e2e5fe50.png" alt="application listing screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will then be taken to the application creation wizard. Choose the &lt;strong&gt;Single-Page App&lt;/strong&gt; button and click &lt;strong&gt;Next&lt;/strong&gt; at the bottom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fsingle-page-app-screen-99a750aba6859fdd722e917183de876bba2e309b9f6a57cde3393f1edfad9c8a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fsingle-page-app-screen-99a750aba6859fdd722e917183de876bba2e309b9f6a57cde3393f1edfad9c8a.png" alt="single page app screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, you will see the default settings provided by the single-page application template. Change the name of the application to something more descriptive, like "Membership Application". Also, change the base URIs and the login redirect URIs settings to use port 3000 because that is where your application will be running. The rest of the default settings are fine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fsingle-page-app-settings-screen-61feebc659675ed7092195b6d31a95e377513250464c50409b2771387c62c22d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fsingle-page-app-settings-screen-61feebc659675ed7092195b6d31a95e377513250464c50409b2771387c62c22d.png" alt="single page app settings screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click the &lt;strong&gt;Done&lt;/strong&gt; button at the bottom.&lt;/p&gt;

&lt;p&gt;Once the application has been created, select it from the applications listing, and click on the &lt;strong&gt;General&lt;/strong&gt; tab to view the general settings for your 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%2Fbuild-user-registration-with-node-react-and-okta%2Fgeneral-settings-tab-795561b2ce11a688a8ca48f7af9b55c58d727e12895f2b794a8e95fbd01841a1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fgeneral-settings-tab-795561b2ce11a688a8ca48f7af9b55c58d727e12895f2b794a8e95fbd01841a1.png" alt="general settings tab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the bottom, you will see a &lt;strong&gt;Client ID&lt;/strong&gt; setting (yours won't be blurred out, obviously). Copy this to use in your React application. You will also need your Okta organization URL, which you can find at the top left of the dashboard page. It will probably look something like “&lt;a href="https://dev-XXXXXX.oktapreview.com%E2%80%9D" rel="noopener noreferrer"&gt;https://dev-XXXXXX.oktapreview.com”&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Authentication to the ReactJS Application
&lt;/h2&gt;

&lt;p&gt;Now that the application is created, add authentication using Okta by adding a couple of npm dependencies. From the &lt;code&gt;client&lt;/code&gt; folder run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @okta/okta-react react-router-dom &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if you're using the &lt;a href="https://yarnpkg.com" rel="noopener noreferrer"&gt;yarn&lt;/a&gt; package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add @okta/okta-react react-router-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a file to the &lt;code&gt;client/src&lt;/code&gt; folder called &lt;code&gt;app.config.js&lt;/code&gt;. The contents of the file are:&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;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;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{yourOktaDomain}&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;{yourOktaOrgUrl}/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;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="o"&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, setup the &lt;code&gt;index.js&lt;/code&gt; file to use the React Router and Okta's React SDK. When the &lt;code&gt;index.js&lt;/code&gt; file is complete, it will 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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&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;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserRouter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Router&lt;/span&gt; &lt;span class="p"&gt;}&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;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Security&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;./index.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;config&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.config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;registerServiceWorker&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;./registerServiceWorker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onAuthRequired&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;history&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Security&lt;/span&gt; &lt;span class="nx"&gt;issuer&lt;/span&gt;&lt;span class="o"&gt;=&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;issuer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;redirect_uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect_uri&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;onAuthRequired&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onAuthRequired&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Security&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Router&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;registerServiceWorker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once complete, you will have added the &lt;code&gt;BrowserRouter&lt;/code&gt; component (aliased as "Router") from the React Router, and the &lt;code&gt;Security&lt;/code&gt; component from Okta's React SDK. Also that the &lt;code&gt;app.config.js&lt;/code&gt; file is imported as "config" so that you can use the config values in the properties required by the &lt;code&gt;Security&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;You will also have surrounded the &lt;code&gt;App&lt;/code&gt; component with the &lt;code&gt;Router&lt;/code&gt; and &lt;code&gt;Security&lt;/code&gt; components, passing in the values specified. The &lt;code&gt;onAuthRequired&lt;/code&gt; method, simply tells Okta's React SDK that when somebody tries to access a secure route and they are not logged in, redirect them to the login page.&lt;/p&gt;

&lt;p&gt;Everything else will have come from the &lt;code&gt;create-react-app&lt;/code&gt; command you ran previously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Pages to the ReactJS App
&lt;/h2&gt;

&lt;p&gt;Before adding any routes to the React app, create some components to handle the routes you want to add.&lt;/p&gt;

&lt;p&gt;Add a &lt;code&gt;components&lt;/code&gt; folder to the &lt;code&gt;client/src&lt;/code&gt; folder. This is where all your components will live and the easiest way to organize them. Then create a &lt;code&gt;home&lt;/code&gt; folder for your home page components. For now there will be just one, but there may be more components used only for the home page later. Add a &lt;code&gt;HomePage.js&lt;/code&gt; file to the folder with the following contents:&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;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&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="nf"&gt;render&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;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;This is all you really need for the home page at the moment. The most important point is to make the HomePage component a class type. Even though right now it only contains a single &lt;code&gt;h1&lt;/code&gt; tag, it is meant to be a "page", meaning it will likely contain other components, so it's important that it be a container component.&lt;/p&gt;

&lt;p&gt;Next, create an &lt;code&gt;auth&lt;/code&gt; folder in &lt;code&gt;components&lt;/code&gt;. This is where all components that have to do with authentication will live. In that folder, create a &lt;code&gt;LoginForm.js&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;The first thing to note is that you’ll be using the &lt;code&gt;withAuth&lt;/code&gt; higher-order component from Okta’s React SDK to wrap the entire login form. This adds a prop to the component called &lt;code&gt;auth&lt;/code&gt;, making it possible to access things like the &lt;code&gt;isAuthenticated&lt;/code&gt; and &lt;code&gt;redirect&lt;/code&gt; functions on that higher-order component.&lt;/p&gt;

&lt;p&gt;The code for the &lt;code&gt;LoginForm&lt;/code&gt; component is as follows:&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;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OktaAuth&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-auth-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withAuth&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;withAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginForm&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;sessionToken&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="na"&gt;error&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="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oktaAuth&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;OktaAuth&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&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;handleSubmit&lt;/span&gt; &lt;span class="o"&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;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleUsernameChange&lt;/span&gt; &lt;span class="o"&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;handleUsernameChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handlePasswordChange&lt;/span&gt; &lt;span class="o"&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;handlePasswordChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;username&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;sessionToken&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;sessionToken&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;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;handleUsernameChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;handlePasswordChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&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;props&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;redirect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sessionToken&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error-message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&amp;gt; :&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;    &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&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;handleSubmit&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;errorMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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;handleUsernameChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;
            &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
            &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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;handlePasswordChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other thing of note here is the &lt;code&gt;OktaAuth&lt;/code&gt; library being imported. This is the base library for doing things like signing in using the Okta application you created previously. You'll notice an &lt;code&gt;OktaAuth&lt;/code&gt; object being created in the constructor that gets a property of &lt;code&gt;baseUrl&lt;/code&gt; passed to it. This is the URL for the issuer that is in your &lt;code&gt;app.config.js&lt;/code&gt; file. The &lt;code&gt;LoginForm&lt;/code&gt; component is meant to be contained in another component, so you'll have to create a &lt;code&gt;LoginPage.js&lt;/code&gt; file to contain this component. You'll use the &lt;code&gt;withAuth&lt;/code&gt; higher-order component again, to get access to the &lt;code&gt;isAuthenticated&lt;/code&gt; function. The contents of &lt;code&gt;LoginPage.js&lt;/code&gt; will be:&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;React&lt;/span&gt;&lt;span class="p"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Redirect&lt;/span&gt; &lt;span class="p"&gt;}&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;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LoginForm&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;./LoginForm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withAuth&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;withAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Login&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkAuthentication&lt;/span&gt; &lt;span class="o"&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkAuthentication&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticated&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;props&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;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidUpdate&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Redirect&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="err"&gt;:
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoginForm&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&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;Although it's a bit less than what's in the login form component, there are still some important pieces to point out here.&lt;/p&gt;

&lt;p&gt;Again, you're using the &lt;code&gt;withAuth&lt;/code&gt; higher-order component. This will be a recurring theme for every component that needs to use Okta's authentication or authorization process. In this case, it's primarily used to get the &lt;code&gt;isAuthenticated&lt;/code&gt; function. The &lt;code&gt;checkAuthentication()&lt;/code&gt; method is executed in the constructor and in the &lt;code&gt;componentDidUpdate&lt;/code&gt; lifecycle method to ensure that when the component is created it is checked and every subsequent change to the component checks again.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;isAuthenticated&lt;/code&gt; returns true, then it is set in the component's state. It is then checked in the render method to decide whether to show the &lt;code&gt;LoginForm&lt;/code&gt; component, or to redirect to the user's profile page, a component you'll create next.&lt;/p&gt;

&lt;p&gt;Now create the &lt;code&gt;ProfilePage.js&lt;/code&gt; component inside the &lt;code&gt;auth&lt;/code&gt; folder. The contents of the component are:&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;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withAuth&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;withAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProfilePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCurrentUser&lt;/span&gt; &lt;span class="o"&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;getCurrentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getCurrentUser&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;props&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="nf"&gt;then&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;=&amp;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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidMount&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;getCurrentUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;section&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user-profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;Profile&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/section&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;withAuth&lt;/code&gt; component here gives you access to the &lt;code&gt;getUser&lt;/code&gt; function. Here, it's been called from &lt;code&gt;componentDidMount&lt;/code&gt; which is a common place for pulling data that will be used in the &lt;code&gt;render&lt;/code&gt; method. The only odd thing you might see is the first line of the &lt;code&gt;render&lt;/code&gt; method that renders nothing until there is actually a user returned from the &lt;code&gt;getUser&lt;/code&gt; asynchronous call. Once there is a user in the state, it then renders the profile content, which in this case is just displaying the currently logged in user's name.&lt;/p&gt;

&lt;p&gt;Next, you'll add a registration component. This could be done just like the login form, where there is a &lt;code&gt;LoginForm&lt;/code&gt; component that is contained in a &lt;code&gt;LoginPage&lt;/code&gt; component. In order to demonstrate another way to display this, you'll just create a &lt;code&gt;RegistrationForm&lt;/code&gt; component that will be the main container component. Create a &lt;code&gt;RegistrationForm.js&lt;/code&gt; file in the &lt;code&gt;auth&lt;/code&gt; folder with the following content:&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;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;OktaAuth&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-auth-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withAuth&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;config&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.config&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;withAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RegistrationForm&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oktaAuth&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;OktaAuth&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkAuthentication&lt;/span&gt; &lt;span class="o"&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkAuthentication&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;handleSubmit&lt;/span&gt; &lt;span class="o"&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;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleFirstNameChange&lt;/span&gt; &lt;span class="o"&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;handleFirstNameChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleLastNameChange&lt;/span&gt; &lt;span class="o"&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;handleLastNameChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleEmailChange&lt;/span&gt; &lt;span class="o"&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;handleEmailChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handlePasswordChange&lt;/span&gt; &lt;span class="o"&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;handlePasswordChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&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;props&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;getIdToken&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;sessionToken&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidUpdate&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;handleFirstNameChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;handleLastNameChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;handleEmailChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;handlePasswordChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&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;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&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;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;then&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;=&amp;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;oktaAuth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;username&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;password&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;sessionToken&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;sessionToken&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;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&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;props&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;redirect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;sessionToken&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="k"&gt;return&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;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&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;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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;handleEmailChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;First&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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;handleFirstNameChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Last&lt;/span&gt; &lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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;handleLastNameChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
          &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="o"&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;handlePasswordChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;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;This component looks a lot like the &lt;code&gt;LoginForm&lt;/code&gt; component with the exception that it calls the Node API (that you’ll build in a moment) that will handle doing the registration. Once the registration is completed by the Node API, the component logs the newly created user in, and the render method (when it sees a session token in the state) redirects the user to the home page of the application.&lt;/p&gt;

&lt;p&gt;You may also notice the &lt;code&gt;sessionToken&lt;/code&gt; property on the component’s state. This is set by the &lt;code&gt;handleSubmit()&lt;/code&gt; function for the purpose of handling the login if the registration is successful. Then it is also used by the &lt;code&gt;render()&lt;/code&gt; method to do the redirect once the login has completed, and a token has been received.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add Routes to the React App
&lt;/h2&gt;

&lt;p&gt;First, add a navigation component for the routes you’ll be adding. In the &lt;code&gt;client/src/components&lt;/code&gt; folder, add a folder called &lt;code&gt;shared&lt;/code&gt;. This will be the place where all components that are used in several places in the application will be located. In that new folder, add a file called &lt;code&gt;Navigation.js&lt;/code&gt;. The file contains a basic component with links to all the pages in the app.&lt;/p&gt;

&lt;p&gt;You’ll need to wrap the navigation component in the &lt;code&gt;withAuth&lt;/code&gt; higher-order component. That way, you can check to see if there is an authenticated user and display the login or logout button as appropriate.&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;React&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="p"&gt;}&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;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;withAuth&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;withAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Navigation&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkAuthentication&lt;/span&gt; &lt;span class="o"&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkAuthentication&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authenticated&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;props&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;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;componentDidUpdate&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;checkAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;authNav&lt;/span&gt; &lt;span class="o"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth-nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;javascript:void(0)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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;props&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="nx"&gt;logout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Logout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Profile&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&amp;gt; &lt;/span&gt;&lt;span class="err"&gt;:
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auth-nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;javascript:void(0)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&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;props&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="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Login&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Register&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;nav&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;li&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;authNav&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/nav&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Now that you have components available to handle all the routes, create the routes to go with them. Update the &lt;code&gt;App.js&lt;/code&gt; file so that the final version looks like:&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;React&lt;/span&gt;&lt;span class="p"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="p"&gt;}&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;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SecureRoute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ImplicitCallback&lt;/span&gt; &lt;span class="p"&gt;}&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-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Navigation&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/shared/Navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;HomePage&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/home/HomePage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;RegistrationForm&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/auth/RegistrationForm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;config&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.config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LoginPage&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/auth/LoginPage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ProfilePage&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/auth/ProfilePage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Navigation&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="o"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LoginPage&lt;/span&gt; &lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;=&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;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;} /&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/implicit/callback&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ImplicitCallback&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/register&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;RegistrationForm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SecureRoute&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ProfilePage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;There are a couple of things of note here. The import of the &lt;code&gt;SecureRoute&lt;/code&gt; and &lt;code&gt;ImplicitCallback&lt;/code&gt; components from Okta's React SDK. The &lt;code&gt;ImplicitCallback&lt;/code&gt; component handles the callback from the authentication flow to ensure there is an endpoint within the React application to catch the return call from Okta. The &lt;code&gt;SecureRoute&lt;/code&gt; component allows you to secure any route and redirect unauthenticated users to the login page.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Route&lt;/code&gt; component from React Router does exactly what you'd expect: it takes a path that the user has navigated to and sets a component to handle that route. The &lt;code&gt;SecureRoute&lt;/code&gt; component does an extra check to ensure the user is logged in before allowing access to that route. If they are not then the &lt;code&gt;onAuthRequired&lt;/code&gt; function in &lt;code&gt;index.js&lt;/code&gt; will be called to force the user to the login page.&lt;/p&gt;

&lt;p&gt;The only other really odd-looking thing here is the route for the login path. Instead of simply setting a component to handle the path, it runs a &lt;code&gt;render&lt;/code&gt; method that renders the &lt;code&gt;LoginPage&lt;/code&gt; component and sets the baseUrl from the configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add API Endpoints to the Node App
&lt;/h2&gt;

&lt;p&gt;You may remember that the Node API is doing the registration, so you'll need to add the endpoint to the Node app to handle that call. To do that, you'll need to add Okta's Node SDK. From the ‘api’ folder run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @okta/okta-sdk-nodejs &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you'll change the &lt;code&gt;users.js&lt;/code&gt; file in &lt;code&gt;api/routes&lt;/code&gt;. The file will look like:&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;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Router&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;oktaClient&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;../lib/oktaClient&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/* Create a new User (register). */&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;post&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="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="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;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&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;newUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&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;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&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;oktaClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newUser&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;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The biggest things of note here are the importing of the &lt;code&gt;lib/oktaClient&lt;/code&gt; (which you'll add in a moment), the call to the &lt;code&gt;createUser&lt;/code&gt; function on  &lt;code&gt;oktaClient&lt;/code&gt;, and the shape of the &lt;code&gt;newUser&lt;/code&gt; object. The shape of the &lt;code&gt;newUser&lt;/code&gt; object is documented &lt;a href="https://developer.okta.com/docs/api/resources/users" rel="noopener noreferrer"&gt;in Okta's API documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For your Node application to make calls to your Okta application, it will need an API token. To create one, go into your Okta developer dashboard, hover over the API menu option and click on Tokens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fokta-api-tokens-screen-b166c1701dc90dc37780dd5da4c9d796ccb527de7880dcd31645615eaab58159.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fokta-api-tokens-screen-b166c1701dc90dc37780dd5da4c9d796ccb527de7880dcd31645615eaab58159.png" alt="okta api tokens screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From there click Create Token. Give the token a name like "Membership" and click Create Token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fcreate-token-screen-2e20d4e5d1257452e462db66b396d07c2ad5bb768b67c994bfa9a0309d6c11b7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fcreate-token-screen-2e20d4e5d1257452e462db66b396d07c2ad5bb768b67c994bfa9a0309d6c11b7.png" alt="create token screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the token to a safe location for use later.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;oktaClient.js&lt;/code&gt; in a new folder called &lt;code&gt;lib&lt;/code&gt; in the Node application. The file will configure a &lt;code&gt;Client&lt;/code&gt; object from Okta's Node SDK using the API token you just created 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;okta&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/okta-sdk-nodejs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;okta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;orgUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{yourOktaDomain}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{yourApiToken}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;app.js&lt;/code&gt; file at the root of the Node app, update the file to have all calls route to &lt;code&gt;/api/&amp;lt;something&amp;gt;&lt;/code&gt;. You'll see a section below the block of &lt;code&gt;app.use&lt;/code&gt; statements. Change the route set up so that it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your Node app is still running, you will need to stop the app (with CTRL+C) and rerun it (with &lt;code&gt;npm start&lt;/code&gt;) for the updates to take effect.&lt;/p&gt;

&lt;p&gt;Even though the site still needs some serious style love, you will now be able to register users, log in with the newly created user and get the logged in user's profile for display on the profile page!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fuser-profile-page-aea5259fa9066be2be7c36fa33aaf79eaccf57f8e6d0e11b5a0611d170037f04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdeveloper.okta.com%2Fassets%2Fblog%2Fbuild-user-registration-with-node-react-and-okta%2Fuser-profile-page-aea5259fa9066be2be7c36fa33aaf79eaccf57f8e6d0e11b5a0611d170037f04.png" alt="user profile page"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;If you want to learn more about the technologies used in this articles, you can check out the documentation for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Okta's &lt;a href="https://developer.okta.com/okta-sdk-nodejs/jsdocs/index.html" rel="noopener noreferrer"&gt;Node SDK&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Okta’s &lt;a href="https://developer.okta.com/code/react/" rel="noopener noreferrer"&gt;React SDK&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, check out other articles using Okta for authentication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Randall Degges’s article on Okta in a &lt;a href="https://developer.okta.com/blog/2017/10/19/use-openid-connect-to-build-a-simple-node-website" rel="noopener noreferrer"&gt;Simple Node Website&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;My article using the &lt;a href="https://developer.okta.com/blog/2017/03/30/react-okta-sign-in-widget" rel="noopener noreferrer"&gt;Okta Sign-In Widget in React&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Matt Raible’s Article on &lt;a href="https://developer.okta.com/blog/2017/07/20/the-ultimate-guide-to-progressive-web-applications" rel="noopener noreferrer"&gt;Progressive Web Apps&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As always, if you have questions, comments, or concerns about the article you can post a comment below, email me at &lt;a href="mailto:lee.brandt@okta.com"&gt;lee.brandt@okta.com&lt;/a&gt; or post your questions to the &lt;a href="https://devforum.okta.com" rel="noopener noreferrer"&gt;developer forums&lt;/a&gt;. For more articles and tutorials, follow us on Twitter &lt;a href="https://twitter.com/oktadev" rel="noopener noreferrer"&gt;@OktaDev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>react</category>
      <category>auth</category>
    </item>
  </channel>
</rss>
