<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Richard Banks</title>
    <description>Posts and Articles from Richard Banks</description>
    <link>https://www.richard-banks.org/</link>
    <atom:link href="https://www.richard-banks.org/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 02 Aug 2019 02:16:09 +0000</pubDate>
    <lastBuildDate>Fri, 02 Aug 2019 02:16:09 +0000</lastBuildDate>
    <generator>Jekyll v3.8.5</generator>
    
      <item>
        <title>Improving performance with .NET Core 3.0</title>
        <description>&lt;p&gt;The week I gave a talk at the Sydney Alt.Net Meetup about using .NET Core 3.0, Span&lt;T&gt;, stackalloc, and other newer .NET features to improve performance of an application.&lt;/T&gt;&lt;/p&gt;

&lt;p&gt;In it I showed a specific scenario where I used a PDF library (&lt;a href=&quot;https://uglytoad.github.io/PdfPig/&quot;&gt;PdfPig&lt;/a&gt;) to count the words in a PDF file, and in less than an hour improved the performance by over 30%.&lt;/p&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;daf7b1bc3fd04e86841c0f43dad7f8b7&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;Much of the talk centered around actually making the performance improvements and shortly I’ll create a video showing that side of the talk, and how PerfView and benchmarkDotNet can be used to help.&lt;/p&gt;

&lt;p&gt;For now, you can look at the code at various stages of improvement by jumping between the different branches of my cloned PdfPig repo at https://github.com/rbanks54/PdfPig.&lt;/p&gt;

&lt;p&gt;Here are the branches you might want to look at:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;master&lt;/strong&gt;: the code “as-is”, simply the snapshot of the original library, with no changes.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;startPoint&lt;/strong&gt;: Converted to .NET Core 3.0 and with a “performanceTester” utility you can run to see overall performance for our test scenario. You can switch the csproj to netcoreapp2.2 to see the difference between Core 3.0 and Core 2.2&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;numericTokens&lt;/strong&gt;: Added microbenchmarking and improved performance of the numeric token parser. Run the benchmarks program to see the numbers&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;NameTokens&lt;/strong&gt;: microbenchmarking, with multiple approaches. Use the benchmarks to compare performance differences of various approaches. Run with “-m” to see the memory usage stats.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;both-tokens&lt;/strong&gt;: code with both the numeric and name token improvements in it. Run the performanceTester to compare with the original code.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 02 Aug 2019 01:15:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2019/08/imrproving-performance-with-net-core-3.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2019/08/imrproving-performance-with-net-core-3.html</guid>
        
        
      </item>
    
      <item>
        <title>Code splitting in Vue</title>
        <description>&lt;p&gt;I have a small personal project I’m building with Vue and Webpack v4. I noticed that the production bundle size was starting to get a bit large (3.4 Mb).&lt;/p&gt;

&lt;p&gt;A bundle of this size will be slow to load and people on slow connections might think the web app is failing to load and leave the site.&lt;/p&gt;

&lt;p&gt;Time to do some code splitting.&lt;/p&gt;

&lt;p&gt;If you’ve not heard of the term before, code splitting aims to reduce the size of the JavaScript loaded for a site to just the code needed to serve up the initial view. Any JavaScript needed after that is loaded asynchronously, and on demand.&lt;/p&gt;

&lt;p&gt;With Vue this is really quite easy!&lt;/p&gt;

&lt;p&gt;How easy, you ask? Let’s have a look.&lt;/p&gt;

&lt;h3 id=&quot;route-splitting&quot;&gt;Route splitting&lt;/h3&gt;
&lt;p&gt;Since we want the initial bundle to only contain code need for loading the site, we don’t need any of code used elsewhere in our app. Splitting out components loaded only when people navigate elsewhere is perfect for this.&lt;/p&gt;

&lt;p&gt;To given you an example, here’s the extent of my changes needed to split out an admin component into a separate bundle:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Original code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AdminContainer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pages/AdminContainer'&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Changed to&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AdminContainer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* webpackChunkName: &quot;admin-container&quot; */&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pages/AdminContainer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And that comment for the &lt;code class=&quot;highlighter-rouge&quot;&gt;webpackChunkName&lt;/code&gt;? It’s not even required! That’s just so I can name the bundle the way I want.&lt;/p&gt;

&lt;p&gt;And that’s it!
A one line change and we’re all done. Wow!&lt;/p&gt;

&lt;h3 id=&quot;ok-not-quite&quot;&gt;OK, Not quite&lt;/h3&gt;
&lt;p&gt;Yes. I lie a little. I also had to add this single to my &lt;code class=&quot;highlighter-rouge&quot;&gt;.babelrc&lt;/code&gt; file to handle the dynamic import statement:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;plugins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@babel/plugin-syntax-dynamic-import&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

&lt;h3 id=&quot;its-not-just-for-vue-components&quot;&gt;It’s not just for Vue components&lt;/h3&gt;

&lt;p&gt;I use &lt;a href=&quot;http://pdfmake.org&quot;&gt;PdfMake&lt;/a&gt; to create PDF files in the browser, and have put all the code related to generating PDFs in a module I named &lt;code class=&quot;highlighter-rouge&quot;&gt;pdfGenerator&lt;/code&gt; (I know, so creative!).&lt;/p&gt;

&lt;p&gt;Instead of having all the PDF generation code in my initial bundle, I can split it out into it’s own bundle and only load it on demand.&lt;/p&gt;

&lt;p&gt;We can still use the dynamic import statement, but we have to keep in mind that the dynamic import returns a promise, and when the promise resolves our callback will be passed the module that was loaded.&lt;/p&gt;

&lt;p&gt;So, my code for generating a PDF now becomes something like this&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pdfGenerator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'@/services/pdfGenerator'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//.. rest of Vue component&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;pdfGenerator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;generate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//the default export from the imported module&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;generate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;someValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;someOtherValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s a little more code, but still really easy to use dynamic imports and the approach means we can separately load JavaScript needed on a function specific basis, not just when Vue components are loaded.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;By using just some basic route-based splitting and delaying the loading of the PDF functionality until it’s needed, I turned what was a 3.4 Mb bundle into a 1.2 Mb bundle in about 20 minutes of work, including testing time.&lt;/p&gt;

&lt;p&gt;I’m pretty happy with that, and there’s still more I can do to further optimise the initial bundle size and make the load time of my web app even quicker.&lt;/p&gt;
</description>
        <pubDate>Sun, 20 Jan 2019 21:30:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2019/01/code-splitting-in-vue.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2019/01/code-splitting-in-vue.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 9</title>
        <description>&lt;p&gt;This is part 9 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 9 - Refreshing identity tokens with Vue.js (this post)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;refresh-tokens&quot;&gt;Refresh tokens&lt;/h2&gt;

&lt;p&gt;You’ll find that if you leave the Vue app running for long enough that eventually the identity token will expire and you’ll need to sign in again.&lt;/p&gt;

&lt;p&gt;If this happens too regularly users will complain of a poor user experience and get a bit annoyed with your application. Let’s have a look at how we can configure our application to automatically refresh the identity token once it gets close to expiring.&lt;/p&gt;

&lt;p&gt;Ideally, we don’t want our users to know that the token has been refreshed. We want  token renewal to occur without interrupting the user experience or breaking the behaviour of the application in any way.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;oidc-client&lt;/code&gt; provides this functionality for us via its automatic silent renewal feature.&lt;/p&gt;

&lt;p&gt;Let’s add this to our code by adjusting the configuration of the &lt;code class=&quot;highlighter-rouge&quot;&gt;UserManager&lt;/code&gt; in &lt;code class=&quot;highlighter-rouge&quot;&gt;services/security.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the following properties where we create the UserManager object&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nx&quot;&gt;automaticSilentRenew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;silent_redirect_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://localhost:5000/static/silent-renew.html'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;accessTokenExpiringNotificationTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll note that &lt;code class=&quot;highlighter-rouge&quot;&gt;silent-renew.html&lt;/code&gt; is a static page, not a Vue component. This is to avoid the overhead of creating a new Vue instance, and to limit any risk of interrupting work happening in the main application. The &lt;code class=&quot;highlighter-rouge&quot;&gt;silent-renew.html&lt;/code&gt; page is simply a callback to complete the token renewal process and we’re only using it to update our token stored in the browser’s local storage. We don’t need to update and any of Vue’s state information.&lt;/p&gt;

&lt;p&gt;Now, because we’re changing the client to support silent renewal, we need to adjust the client registration in IdentityServer as well.&lt;/p&gt;

&lt;p&gt;We’re going to shorten our token lifetime to 90 seconds to avoid waiting 2 hours for tokens to expire, and we’ll also add a new &lt;code class=&quot;highlighter-rouge&quot;&gt;RedirectUri&lt;/code&gt;, enable &lt;code class=&quot;highlighter-rouge&quot;&gt;AllowOfflineAccess&lt;/code&gt; and disable the &lt;code class=&quot;highlighter-rouge&quot;&gt;RequireConsent&lt;/code&gt; flag. For this post we’ll also be using a sliding expiration approach so that as long as the tokens keep getting regularly refreshed, you’ll remain logged in.&lt;/p&gt;

&lt;p&gt;Here’s the extra client configuration code you need in &lt;code class=&quot;highlighter-rouge&quot;&gt;Config.cs&lt;/code&gt; of your &lt;code class=&quot;highlighter-rouge&quot;&gt;IdentityServer&lt;/code&gt; project&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;AllowOfflineAccess&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;AccessTokenLifetime&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// 1.5 minutes&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;AbsoluteRefreshTokenLifetime&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;RefreshTokenUsage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TokenUsage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OneTimeOnly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;RefreshTokenExpiration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TokenExpiration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sliding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;UpdateAccessTokenClaimsOnRefresh&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;RequireConsent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;RedirectUris&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;&quot;https://localhost:5000/callback&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;&quot;https://localhost:5000/static/silent-renew.html&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Back in our &lt;code class=&quot;highlighter-rouge&quot;&gt;vue-app&lt;/code&gt;, we now need to implement the silent-renew callback page. We’ll need to include the &lt;code class=&quot;highlighter-rouge&quot;&gt;oidc-client&lt;/code&gt; and a simple call to trigger the callback completion method.&lt;/p&gt;

&lt;p&gt;Create a static folder in &lt;code class=&quot;highlighter-rouge&quot;&gt;/public&lt;/code&gt;, and then create a &lt;code class=&quot;highlighter-rouge&quot;&gt;/public/static/silent-renew.html&lt;/code&gt; page with the following content.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Silent Renew Token&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'oidc-client.min.js'&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;      
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'renewing tokens'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UserManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;userStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;WebStorageStateStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})})&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signinSilentCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since this is static content and we’re not building anything with Webpack, we need to copy &lt;code class=&quot;highlighter-rouge&quot;&gt;oidc-client.min.js&lt;/code&gt; from &lt;code class=&quot;highlighter-rouge&quot;&gt;vue-app\node_modules\oidc-client\dist\oidc-client.min.js&lt;/code&gt; into the &lt;code class=&quot;highlighter-rouge&quot;&gt;/public/static&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;If you haven’t already done so, build and restart both your identity server and your vue-app sites.&lt;/p&gt;

&lt;p&gt;Browse to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; page and ensure you can still make the secure API call.&lt;/p&gt;

&lt;p&gt;Now you’ll just have to wait 90 seconds to see if your token refreshes. You should be able to see network activity using your browser’s developer tools, and you should see the &lt;code class=&quot;highlighter-rouge&quot;&gt;&quot;renewing tokens&quot;&lt;/code&gt; message in the console.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/token_renewal.png&quot; alt=&quot;token renewal&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;That’s it! We’re done!&lt;/p&gt;

&lt;p&gt;I hope you’ve found this series useful and that it helps you in your development efforts!&lt;/p&gt;

&lt;p&gt;If you have any feedback, reach out and let me know. Also, if you notice any bugs or issues with the code, head over to GitHub project and let me know there.&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 03:00:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part9.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part9.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 8</title>
        <description>&lt;p&gt;This is part 8 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 8 - Calling a secured API from Vue.js (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;calling-a-secured-api-from-vuejs&quot;&gt;Calling a secured API from Vue.js&lt;/h2&gt;

&lt;p&gt;Hopefully you’ve been following along with the previous posts. You should now have a working Vue.js app, be prompted to log in via IdentityServer when browsing to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; page, and can show data returned from an unsecured API on that page.&lt;/p&gt;

&lt;p&gt;Let’s extend the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; page to show data from our secured &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/services&lt;/code&gt; API.&lt;/p&gt;

&lt;p&gt;Adjust the &lt;code class=&quot;highlighter-rouge&quot;&gt;about.vue&lt;/code&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;template&amp;gt;&lt;/code&gt; as follows:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;click=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callApi&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Call API&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;click=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callSecureApi&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Call Secure API&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v-for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(service,index) in services&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;:key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;service.iconUri&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;service.uri&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add a services property to the component’s data in the &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; section&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;no data yet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then add a new method for calling the API and populating data with the result&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callSecureApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://localhost:5000/api/services&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;services&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'secure api call failed'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because this is a secured API, we need to provide an identity token in the request headers when making the call. If we had to write code to do this every time we made a API call it would be a painful experience, and no one wants that!&lt;/p&gt;

&lt;p&gt;This is where Axios becomes very handy! Axios supports the concept of interceptors. Methods that run before or after network calls. We’ll add an interceptor before each network call, so that any time we have a valid security token we’ll automatically attach it to the request headers.&lt;/p&gt;

&lt;p&gt;Head over to &lt;code class=&quot;highlighter-rouge&quot;&gt;main.js&lt;/code&gt; one more time and import the axios module&lt;/p&gt;
&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'axios'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now add a request interceptor for Axios to the end of the file.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;interceptors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;authToken&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;authToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Authorization&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`Bearer &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;authToken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//What do you want to do when a call fails?&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll see that we’re using a variable &lt;code class=&quot;highlighter-rouge&quot;&gt;'v'&lt;/code&gt; that we haven’t defined yet.&lt;/p&gt;

&lt;p&gt;This will be the root Vue instance, which we need if we want to access the UserManager information. Adjust the Vue declaration as follows&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Vue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//…&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now let’s cross our fingers, take a deep breath, and give it a try!&lt;/p&gt;

&lt;p&gt;Browse to the site (https://localhost:5000), navigate to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; page, sign in (if prompted), and then click the button to call the secure API.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/secured_api_result.png&quot; alt=&quot;secured API result&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Hopefully, you haven’t missed anything along the way and it all works for you. Raise your fists in the air in victory and give yourself a pay raise!&lt;/p&gt;

&lt;p&gt;A few things to note: Because we haven’t implemented any logout functionality if you ever want to reset and sign in from scratch, you’ll need to browse to IdentityServer and click the logout button (it’s under your user name),and you’ll have to clear your browser local storage to remove any tokens stored there. Alternatively, just start an incognito/inPrivate browser session and use that.&lt;/p&gt;

&lt;p&gt;If you want to implement the sign out process yourself, you’ll need to call the &lt;code class=&quot;highlighter-rouge&quot;&gt;singoutRedirect()&lt;/code&gt; method from &lt;code class=&quot;highlighter-rouge&quot;&gt;oidc-client&lt;/code&gt;, but we won’t be doing that in this series.&lt;/p&gt;

&lt;p&gt;We’re pretty much done, but there’s one last thing we should look at. How do we refresh our identity tokens so we’re not signed out so regularly?&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 02:30:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part8.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part8.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 7</title>
        <description>&lt;p&gt;This is part 7 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 7 - Securing a router view in Vue.js (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;securing-a-route-in-vuejs&quot;&gt;Securing a route in Vue.js&lt;/h2&gt;

&lt;p&gt;Just to recap on what we’ve done so far… we have an IdentityServer instance up and running, we have a site serving up an ASP.NET Core Web API and the built JavaScript files from our Vue.js SPA, and we’ve been able to retrieve data from our back end API and show it on the browser. Have a look at the prior parts in this series if you need to catch up.&lt;/p&gt;

&lt;p&gt;We now want to secure access to the About page so that people are automatically signed in when they browse the about page. This will also mean we have the necessary security tokens available when we make the call to the secured API (in the next post).&lt;/p&gt;

&lt;p&gt;When it comes to routing, the &lt;a href=&quot;https://router.vuejs.org/&quot;&gt;Vue Router&lt;/a&gt; is the library of choice for Vue. With &lt;code class=&quot;highlighter-rouge&quot;&gt;vue-router&lt;/code&gt; we are able to write navigation guards to protect access to URIs. When someone tries to access a secured page, we’re going to see if they have any credentials and if they don’t we’re going to prompt for them (i.e. redirect them to sign in).&lt;/p&gt;

&lt;p&gt;We begin by marking the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; route as secured by adding extra metadata fields to it. Edit the &lt;code class=&quot;highlighter-rouge&quot;&gt;router.js&lt;/code&gt; file and add the meta properties as shown&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/about'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'about'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;requiresAuth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now need to adjust the &lt;code class=&quot;highlighter-rouge&quot;&gt;export&lt;/code&gt; statement. We’ll store the router instance in a variable, and export that variable rather than the object itself. This is so we can perform some other actions with the router instance later in the file.&lt;/p&gt;

&lt;p&gt;Change this code:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To the following:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;//…&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next up; let’s implement the navigation guard. Add this code to the &lt;code class=&quot;highlighter-rouge&quot;&gt;router.js&lt;/code&gt; file&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isAuthenticated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isAuthenticated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//already signed in, we can navigate anywhere&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;matched&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;requiresAuth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//authentication is required. Trigger the sign in process, including the return URI&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'authenticating a protected url:'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//No auth required. We can navigate&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;router.app&lt;/code&gt; variable references the base Vue instance (&lt;a href=&quot;https://router.vuejs.org/api/#router-app&quot;&gt;see the docs&lt;/a&gt;), but it won’t be populated the very first time the router is called. For this reason we provide a default value.&lt;/p&gt;

&lt;p&gt;If this was a more “real-world” application we’d probably be using &lt;a href=&quot;https://vuex.vuejs.org/&quot;&gt;Vuex&lt;/a&gt; or Redux to store authentication data, and we wouldn’t need to access the &lt;code class=&quot;highlighter-rouge&quot;&gt;router.app&lt;/code&gt; value like we’re doing here. Doing that in this series would make it even bigger than it already is, and it’s long enough already so we’ll keep it simplistic for now, work around this little problem, and get on with it. Have a look at how you can manage application state using Vuex once you’ve finished here.&lt;/p&gt;

&lt;p&gt;Those changes made, head over to &lt;code class=&quot;highlighter-rouge&quot;&gt;main.js&lt;/code&gt; and change the contents to look as follows:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globalData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;isAuthenticated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globalMethods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returnPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'yet to be implemented'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Vue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globalData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globalMethods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$mount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#app'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re simply declaring some fields and methods and attaching them to the root Vue instance (because we’re not using Vuex) so we can access them in the router navigation guards.&lt;/p&gt;

&lt;p&gt;If you now browse to the site and navigate to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; page you should see in the browser console a few messages indicating our &lt;code class=&quot;highlighter-rouge&quot;&gt;authenticate()&lt;/code&gt; method is being called&lt;/p&gt;

&lt;h3 id=&quot;signing-in-with-openid-connect&quot;&gt;Signing in with OpenId Connect&lt;/h3&gt;

&lt;p&gt;Great! Let’s get back to implementing our OpenId Connect sign in process.&lt;/p&gt;

&lt;p&gt;We begin by including a JavaScript library that helps with the low-level security handshake and plumbing work. This is the &lt;a href=&quot;https://github.com/IdentityModel/oidc-client-js&quot;&gt;oidc-client&lt;/a&gt; library, written by the IdentityServer team and hosted on GitHub.&lt;/p&gt;

&lt;p&gt;Add this to our vue-app by going to the command line and running&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yarn add oidc-client
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now let’s add a new folder called &lt;code class=&quot;highlighter-rouge&quot;&gt;security&lt;/code&gt; to our &lt;code class=&quot;highlighter-rouge&quot;&gt;/vue-app/src&lt;/code&gt; folder, and create a &lt;code class=&quot;highlighter-rouge&quot;&gt;security.js&lt;/code&gt; file in that folder. This will be where we put our code to handle much of the security and OpenId Connect calls.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;oidc-client&lt;/code&gt; library provides a &lt;code class=&quot;highlighter-rouge&quot;&gt;UserManager&lt;/code&gt; object that we can configure for communicating with IdentityServer. The configuration details we supply here must match the client information we created in IdentityServer, otherwise IdentityServer will reject the connection.&lt;/p&gt;

&lt;p&gt;Let’s get this sorted out by adding the following code:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'oidc-client'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;UserManager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;authority&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://localhost:5443'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;client_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'js'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;redirect_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://localhost:5000/callback'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;response_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'id_token token'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'openid profile api1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;post_logout_redirect_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://localhost:5000/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;userStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;WebStorageStateStore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;localStorage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll note that we’re configuring the &lt;code class=&quot;highlighter-rouge&quot;&gt;userStore&lt;/code&gt; field to use browser local storage. This will prevent information loss when the web app is reloaded.&lt;/p&gt;

&lt;p&gt;If you’re the curious sort and would like to see logging information from within the library simply add the following lines below the UserManager declaration.
It’s entirely option, and if you do use it, remember to disable it in production, okay?&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;logger&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Oidc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We also need to export the &lt;code class=&quot;highlighter-rouge&quot;&gt;UserManager&lt;/code&gt; instance from our module, so add the following to the end of the &lt;code class=&quot;highlighter-rouge&quot;&gt;security.js&lt;/code&gt; file&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, let’s head back to the &lt;code class=&quot;highlighter-rouge&quot;&gt;vue-app/src/main.js&lt;/code&gt; file and flesh out the &lt;code class=&quot;highlighter-rouge&quot;&gt;authenticate()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;We want to check if a user is already known and if not, we want to trigger the sign in process. We’re going to pass along the path we were trying to reach with our sign in request so that when the callback completes we can resume navigation to the target page.&lt;/p&gt;

&lt;p&gt;Here’s an implementation you can use:&lt;/p&gt;

&lt;p&gt;Firstly, let’s import our user manager from our security module.  Add the following line to the top of your file, where the other &lt;code class=&quot;highlighter-rouge&quot;&gt;import&lt;/code&gt; statements are.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'./services/security.js'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then include it in our global data, and implement the authenticate method.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globalData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;isAuthenticated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;globalMethods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;authenticate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returnPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//see if the user details are in local storage&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isAuthenticated&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kr&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signIn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returnPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getUser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;signIn&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;returnPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;returnPath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signinRedirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;returnPath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signinRedirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If your’re not that familiar with vue, &lt;code class=&quot;highlighter-rouge&quot;&gt;this.$root&lt;/code&gt; will return the root vue instance, which is where our methods and data fields are defined.&lt;/p&gt;

&lt;p&gt;We’re still not quite done, but it’s always a good idea to see if things are working before getting too far ahead of ourselves.&lt;/p&gt;

&lt;p&gt;Make sure everything builds correctly, and then browse to the home page (https://localhost:5000).&lt;/p&gt;

&lt;p&gt;If you navigate to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/about&lt;/code&gt; page, you should get redirected to the identity server sign in page.Once you sign in (try: &lt;code class=&quot;highlighter-rouge&quot;&gt;alice/password&lt;/code&gt;) then you’ll be prompted with the permission page.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/alice_signin.png&quot; alt=&quot;sign in as Alice&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/openid_connect_permissions.png&quot; alt=&quot;OpenId connect permission check&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you choose to continue, and you should, you’ll be redirected to the callback page. It won’t work as we haven’t yet implemented it yet, but we’ve proven the previous steps are working.&lt;/p&gt;

&lt;p&gt;Se let’s add a new vue page to &lt;code class=&quot;highlighter-rouge&quot;&gt;/src/views&lt;/code&gt; called &lt;code class=&quot;highlighter-rouge&quot;&gt;Callback.vue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the following code to it.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Sign-in in progress&lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;signinRedirectCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;returnToUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;returnToUrl&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;}&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;returnToUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Unauthorized'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This callback simply completes the sign in process using the &lt;code class=&quot;highlighter-rouge&quot;&gt;oidc-client&lt;/code&gt; library and then redirects to either the home page or the target URL (if we supplied one).&lt;/p&gt;

&lt;p&gt;We’ll also need to add this component to our routing table.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Callback&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'./views/Callback'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//…&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;router&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Router&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;//…&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/callback'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'callback'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Callback&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;//..&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s just one last thing we should do. Now that we can log in, let’s call that secured API and complete the loop!&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 02:00:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part7.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part7.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 6</title>
        <description>&lt;p&gt;This is part 6 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 6 - Calling an HTTP API from Vue.js (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;calling-an-api-from-vuejs&quot;&gt;Calling An API from Vue.js&lt;/h2&gt;

&lt;p&gt;Before we call our secured API, let’s just make sure we can call our unsecured &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/values&lt;/code&gt; API first.&lt;/p&gt;

&lt;p&gt;The default vue app we generated has a simple &lt;code class=&quot;highlighter-rouge&quot;&gt;About&lt;/code&gt; page, so we’ll just repurpose that page instead of adding any new routes to our app.&lt;/p&gt;

&lt;p&gt;To make our API calls we’re going to use the &lt;a href=&quot;https://github.com/axios/axios&quot;&gt;Axios&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;From your command line, ensure you’re in the vue-app folder (i.e. where your JS client source is) and then run&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yarn add axios
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next up, let’s edit the &lt;code class=&quot;highlighter-rouge&quot;&gt;src/views/About.vue&lt;/code&gt; component to display the values return from the &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/values&lt;/code&gt; endpoint.&lt;/p&gt;

&lt;p&gt;Change the template to be:&lt;/p&gt;
&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;about&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;This is an about page&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;v-for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;(item,index) in values&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;:key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;index&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;click=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;callApi&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Call API&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then add a script section to the component (in the same file) for responding to the button click event&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'axios'&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;no data yet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callApi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;axios&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://localhost:5000/api/values&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Ooops!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/script&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Save the file. If you enabled the watch option in your build task you should now be able to switch to the browser and refresh the page.&lt;/p&gt;

&lt;p&gt;Rebuild the app (see &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;part 5&lt;/a&gt;) and navigate to the About page, click the &lt;code class=&quot;highlighter-rouge&quot;&gt;Call API&lt;/code&gt; button. you should see the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/unsecured_results_view.png&quot; alt=&quot;results from unsecured API call&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sure, it’s not the most exciting thing in the world but we’ve proven that we can call our backend correctly and that everything works as expected. When doing software development it’s always good to build something small and then iterate on it until it’s complete.&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 01:30:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part6.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part6.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 5</title>
        <description>&lt;p&gt;This is part 5 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 5 - Creating the Vue.js client (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;creating-a-vuejs-client-app&quot;&gt;Creating a Vue.js Client app&lt;/h2&gt;

&lt;p&gt;For this part of the exercise, we’re going to need a few tools to be installed.&lt;/p&gt;

&lt;p&gt;We’ll need &lt;a href=&quot;https://yarnpkg.com&quot;&gt;yarn&lt;/a&gt; installed (or you can use npm if you prefer), and we’ll also need to add the &lt;a href=&quot;https://cli.vuejs.org/&quot;&gt;vue-cli&lt;/a&gt; utility.&lt;/p&gt;

&lt;p&gt;Assuming you’re using Windows you can either manually install it, or use Chocolatey. Either way, the instructions are at https://yarnpkg.com/en/docs/install, and I’ll leave it as an exercise for you to complete. (P.S. My personal preference is to install using Chocolatey)&lt;/p&gt;

&lt;p&gt;Once Yarn is ready you can install the Vue CLI using&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;yarn global add @vue/cli
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will add the &lt;code class=&quot;highlighter-rouge&quot;&gt;vue&lt;/code&gt; command to your path and allow us to move on with the next step in our plans for world domination. Mwahahaha!!  Oh… sorry. Got carried away there. Yes. Where, were we?&lt;/p&gt;

&lt;h3 id=&quot;create-a-basic-vue-application&quot;&gt;Create a basic vue application&lt;/h3&gt;

&lt;p&gt;Open a command prompt and set your current location to the root folder for your solution (e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;c:\src&lt;/code&gt;) and run the following command:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vue create -n vue-app
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;-n&lt;/code&gt; option tells the vue-cli to not initialise a git repository as this is an existing project and we (should) already have one.&lt;/p&gt;

&lt;p&gt;When prompted, choose to &lt;strong&gt;manually select features&lt;/strong&gt;. Include the &lt;strong&gt;router&lt;/strong&gt; and exclude any linting options, then select the defaults for the prompts that follow by pressing enter. Note that the arrow keys will move between options and the spacebar will toggle the highlighted option.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue-cli.gif&quot; alt=&quot;vue cli in action&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This will create a default application in the &lt;code class=&quot;highlighter-rouge&quot;&gt;src/vue-app&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;When we build our Vue code, we’ll deploy it to the &lt;code class=&quot;highlighter-rouge&quot;&gt;wwwroot&lt;/code&gt; folder of our &lt;code class=&quot;highlighter-rouge&quot;&gt;VueApi&lt;/code&gt; site in order to serve it up to browsers.&lt;/p&gt;

&lt;h3 id=&quot;configure-the-vue-cli-service&quot;&gt;Configure the vue-cli-service&lt;/h3&gt;

&lt;p&gt;Vue provides a service that supports the building and serving JavaScript applications. You can see more about what it does at https://cli.vuejs.org/&lt;/p&gt;

&lt;p&gt;Since we’re going to be serving the JavaScript content from our existing web API site, we won’t need the cli-service’s web server capabilities. We’re only interested in the building and packaging of our vue files for distribution.&lt;/p&gt;

&lt;p&gt;The defaults provided by vue are good for many people, but won’t quite work for us so we’ll need to configure things slightly.&lt;/p&gt;

&lt;p&gt;If we wanted, we could configure everything via JavaScript config files, but since vue-cli provides a handy UI for managing the basics of these configurations, and I know how many people like using UIs, we’ll go down that path instead.&lt;/p&gt;

&lt;p&gt;From your command line, set your current directory to the new &lt;code class=&quot;highlighter-rouge&quot;&gt;vue-app&lt;/code&gt; folder and start the UI by running&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vue ui
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Go to the project manager (http://localhost:8000/project/select) and choose to import an existing project by clicking “Import this folder”&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue_project_manager.png&quot; alt=&quot;vue project manager&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Once the project is loaded, the UI will show you the project dashboard. Select the configuration menu and adjust the setting for the Output Directory to use &lt;code class=&quot;highlighter-rouge&quot;&gt;../vueApi/wwwroot&lt;/code&gt; as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue_project_configuration.png&quot; alt=&quot;vue project configuration&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, head to the tasks section are select the build task.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue_build_parameters.png&quot; alt=&quot;vue build parameters&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click the parameters button and ensure that &lt;code class=&quot;highlighter-rouge&quot;&gt;Modern Mode&lt;/code&gt; is off, the &lt;code class=&quot;highlighter-rouge&quot;&gt;env mode&lt;/code&gt; is set to &lt;code class=&quot;highlighter-rouge&quot;&gt;development&lt;/code&gt;, and set the &lt;code class=&quot;highlighter-rouge&quot;&gt;output directory&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;../vueApi/wwwroot&lt;/code&gt; (the same folder we used in the overall configuration).&lt;/p&gt;

&lt;p&gt;You can also enable &lt;code class=&quot;highlighter-rouge&quot;&gt;watch for changes&lt;/code&gt; so that whenever any of our vue-app source files are saved the vue-cli-service will automatically rebuild our code and copy it to our output folder.&lt;/p&gt;

&lt;p&gt;Start the build task and look in the output tab to ensure some activity is occurring.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue_task_output.png&quot; alt=&quot;vue build output&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The dashboard should also be showing fresh data for you to look at&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue_build_dashboard.png&quot; alt=&quot;vue build dashboard&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;serving-up-the-spa&quot;&gt;Serving up the SPA&lt;/h3&gt;
&lt;p&gt;This is a good start, but before we get too excited we want to ensure we can serve up our the build output to our visitors.&lt;/p&gt;

&lt;p&gt;Head back over to &lt;code class=&quot;highlighter-rouge&quot;&gt;Startup.cs&lt;/code&gt; in the Web API project and in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Configure()&lt;/code&gt; method replace &lt;code class=&quot;highlighter-rouge&quot;&gt;app.UseMvc()&lt;/code&gt; with&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;            &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseDefaultFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseStaticFiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseMvc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;routes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;MapSpaFallbackRoute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;spa-fallback&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;controller&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;CatchAll&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Index&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The CatchAll controller will simply ensure that direct browsing to a non-root URL will still serve up the vue application. Routing in Vue will then determine which components get rendered.&lt;/p&gt;

&lt;p&gt;Add an empty MVC controller named &lt;code class=&quot;highlighter-rouge&quot;&gt;CatchAllController&lt;/code&gt;, and change the &lt;code class=&quot;highlighter-rouge&quot;&gt;Index&lt;/code&gt; method as follows&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IActionResult&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/index.html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;text/html&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OK. Let’s give it a go.&lt;/p&gt;

&lt;p&gt;Start the web app (the VueApi application) and browse to the root at https://localhost:5000. You should see the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vue_app_home_page.png&quot; alt=&quot;vue app home page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Wonderful! We now have our JavaScript build environment up and running, and we’re able to serve up the static content to our site visitors.&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 01:00:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part5.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part5.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 4</title>
        <description>&lt;p&gt;This is part 4 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 4 - Creating and securing an ASP.NET Core Web API (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;creating-and-securing-a-web-api&quot;&gt;Creating and Securing a Web API&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you’re joining the series now, then welcome! We’re assuming you have followed along with the previous parts in the series, so it may be worth familiarising yourself with them before continuing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We’re going to go back to our VueAPI project now, and you may recall that the default project template we use gives us a simple ValuesController.&lt;/p&gt;

&lt;p&gt;We’re going to leave that untouched as we’ll be using it to make sure unauthenticated access is still working as expected.&lt;/p&gt;

&lt;p&gt;We’ll extend our API by adding a new controller that returns a list of objects.  When we get to creating our Vue.js client application we’ll be showing these objects on the page, but only for authenticated users.&lt;/p&gt;

&lt;p&gt;To create the API, right click the &lt;code class=&quot;highlighter-rouge&quot;&gt;Controllers&lt;/code&gt; folder in Visual Studio and choose to add an empty API Controller named ServicesController.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/empty_api_controller.png&quot; alt=&quot;Creating an empty API controller&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’re going to return a list of services my current employer &lt;a href=&quot;https://www.readify.net&quot;&gt;Readify&lt;/a&gt; offers. I know you’d love you to explore and see how Readify can help you but for now I’ll ask you to pay attention to this blog series and visit the site later.&lt;/p&gt;

&lt;p&gt;The API we’ll provide is going to return a collection of objects with service metadata. Here’s an implementation you can copy and paste if you’re following along.&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;[Route(&quot;api/[controller]&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;)]
&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;[ApiController]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServicesController&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ControllerBase&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ActionResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ServiceDto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ServiceDto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServiceDto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Development&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/services/development/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;IconUri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/media/1187/development.png&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServiceDto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Innovation and Design&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/services/innovation-design/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;IconUri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/media/1189/light-bulb.png&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServiceDto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Data and Analytics&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/services/data-analytics/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;IconUri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/media/1184/data.png&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ServiceDto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;DevOps&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/services/devops/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;IconUri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://readify.net/media/1188/devops.png&quot;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServiceDto&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Uri&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IconUri&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We aren’t securing our new API just yet. We need to make sure the API is actually working first, before we add security over the top of it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; &lt;em&gt;I forgot to mention it earlier, but if you haven’t already done so, make sure that your &lt;code class=&quot;highlighter-rouge&quot;&gt;VueApi&lt;/code&gt; project is configured to listen using &lt;code class=&quot;highlighter-rouge&quot;&gt;HTTPS&lt;/code&gt; on port 5000 (the default HTTPS port is 5001). From a security perspective it’s a good practice to always run with HTTPS these days and to get used to developing without any HTTP options at all.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/vueapi_property_page.png&quot; alt=&quot;VueAPI property page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Start the site and browser to http://localhost:5000/api/services and confirm you see a JSON result (use your browsers developer tools to see the network trace).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/unsecured_api_result.png&quot; alt=&quot;VueAPI property page&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;securing-the-api&quot;&gt;Securing the API&lt;/h3&gt;

&lt;p&gt;Great! Now that we’re happy our insecure version works, let’s secure the API!&lt;/p&gt;

&lt;p&gt;Being by adding the &lt;code class=&quot;highlighter-rouge&quot;&gt;IdentityServer4.AccessTokenValidation&lt;/code&gt; package from NuGet&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Install-Package IdentityServer4.AccessTokenValidation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code class=&quot;highlighter-rouge&quot;&gt;Startup.cs&lt;/code&gt; add the following lines to the end of the &lt;code class=&quot;highlighter-rouge&quot;&gt;ConfigureServices()&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;JwtSecurityTokenHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DefaultInboundClaimTypeMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Clear&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddAuthentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuthenticationScheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddIdentityServerAuthentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Authority&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://localhost:5443/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RequireHttpsMetadata&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;api1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re missing references, you may  need to manually add some using statements: &lt;code class=&quot;highlighter-rouge&quot;&gt;using System.IdentityModel.Tokens.Jwt;&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;using Microsoft.AspNetCore.Authentication.JwtBearer;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code class=&quot;highlighter-rouge&quot;&gt;Configure()&lt;/code&gt; method we need to add a call to &lt;code class=&quot;highlighter-rouge&quot;&gt;UseAuthentication()&lt;/code&gt; before we &lt;code class=&quot;highlighter-rouge&quot;&gt;UseMvc()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While we’re here changing code and since we’re not supporting HTTP we can remove the HttpsRedirection call. We can also remove HSTS for now, as we’re not going to production with this code and we don’t need the hassle that HSTS adds just yet.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;Configure&lt;/code&gt; method now looks like the following:&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IApplicationBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IHostingEnvironment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsDevelopment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseDeveloperExceptionPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseAuthentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseMvc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point authentication is configured, but we don’t actually check it anywhere.&lt;/p&gt;

&lt;p&gt;Let’s tell ASP.NET that our &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/services&lt;/code&gt; route is meant to be secure.&lt;/p&gt;

&lt;p&gt;Add the &lt;code class=&quot;highlighter-rouge&quot;&gt;[Authorize]&lt;/code&gt; attribute to the controller class definition&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;api/[controller]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ApiController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Authorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ServicesController&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ControllerBase&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If the &lt;code class=&quot;highlighter-rouge&quot;&gt;[Authorize]&lt;/code&gt; attribute isn’t resolving, check that you have &lt;code class=&quot;highlighter-rouge&quot;&gt;using Microsoft.AspNetCore.Authorization;&lt;/code&gt; included at the top of your file.&lt;/p&gt;

&lt;p&gt;Start the application again and you should now find that any attempt to browse to the &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/services&lt;/code&gt; URI will return a &lt;strong&gt;HTTP 401 Unauthorized&lt;/strong&gt; response, while calls to &lt;code class=&quot;highlighter-rouge&quot;&gt;/api/values&lt;/code&gt; will still work as expected.&lt;/p&gt;

&lt;p&gt;Excellent!&lt;/p&gt;

&lt;p&gt;Unfortunately at this point it will now become a bit tricky to manually test that the authentication is working.&lt;/p&gt;

&lt;p&gt;We would need a known client application to connect to IdentityServer with, we’d need the identity token it would return, and we’d need to attach that as the Bearer token authentication for each call to the API.&lt;/p&gt;

&lt;p&gt;We should probably just go ahead and build the client app now, right?&lt;/p&gt;

&lt;p&gt;I agree! Let’s forge ahead with part 5&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 00:30:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part4.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part4.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 3</title>
        <description>&lt;p&gt;This is part 3 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part2.html&quot;&gt;Part 2 - Creating and Configuring your IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 3 - Adding Google Authentication to IdentityServer (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;adding-google-authentication-to-identity-server&quot;&gt;Adding Google authentication to Identity Server&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you’re joining the series now, then welcome! We’re assuming you have followed along with the previous parts in the series, so it may be worth familiarising yourself with them before continuing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If it’s not already open, open the IdentityServer project we created in the previous parts. Navigate to line 26 of &lt;code class=&quot;highlighter-rouge&quot;&gt;Startup.cs&lt;/code&gt; and you’ll see code to configure default authentication using a standard username and password approach (&lt;code class=&quot;highlighter-rouge&quot;&gt;.AddAuthentication()&lt;/code&gt;) as well as for Google and a 3rd party OpenIdConnect provider.&lt;/p&gt;

&lt;p&gt;We’re not going to use the 3rd Party OpenId Connect provider, so go ahead and delete that code.&lt;/p&gt;

&lt;p&gt;The Google ClientId and Secret values in the Quickstart are default ones provided by the IdentityServer team and are great for learning concepts, but not for running your own identity provider. We’re going to create our own ClientId and Secret.&lt;/p&gt;

&lt;h3 id=&quot;authenticating-your-app-with-google&quot;&gt;Authenticating your app with Google&lt;/h3&gt;

&lt;p&gt;Begin by logging in to the Google Developer Console - https://console.developers.google.com/
and creating a new project in the Google APIs section.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/new_google_api_project.png&quot; alt=&quot;new Google API project&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When the creation operation completes you should be on the API Dashboard. Go directly to the credentials area.&lt;/p&gt;

&lt;p&gt;As a first step we need to configure the OAuth consent screen. Set the &lt;code class=&quot;highlighter-rouge&quot;&gt;Application Name&lt;/code&gt; to &lt;strong&gt;Vue API Demo&lt;/strong&gt; and save the changes.&lt;/p&gt;

&lt;p&gt;From the Credentials tab, click the &lt;code class=&quot;highlighter-rouge&quot;&gt;Create Credentials&lt;/code&gt; drop down and select the &lt;code class=&quot;highlighter-rouge&quot;&gt;OAuth client ID&lt;/code&gt; option&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/google_create_oauth_client_id.png&quot; alt=&quot;Selection to create an OAuth client ID&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Choose Web Application and provide a name of your choice.&lt;/p&gt;

&lt;p&gt;Set the Authorised Redirect URIs to https://localhost:5443/signin-google and then click &lt;code class=&quot;highlighter-rouge&quot;&gt;Create&lt;/code&gt;.  Note that this URL must be &lt;code class=&quot;highlighter-rouge&quot;&gt;/signin-google&lt;/code&gt; from the base URL of your IdentityServer instance.&lt;/p&gt;

&lt;p&gt;You’ll now be shown your &lt;code class=&quot;highlighter-rouge&quot;&gt;Client Id&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Secret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/google_oauth_details.png&quot; alt=&quot;Google OAuth details&quot; /&gt;&lt;/p&gt;

&lt;p&gt;These are the details you need to update in your IdentityServer configuration. Your code in &lt;code class=&quot;highlighter-rouge&quot;&gt;Startup.cs&lt;/code&gt; should now look something like this:&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddAuthentication&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddGoogle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Google&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SignInScheme&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IdentityServerConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExternalCookieAuthenticationScheme&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ClientId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1005450161824-hqg5jq2qnplaskfnjcor4erfb5m8g0rs.apps.googleusercontent.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ClientSecret&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;tPVjh2YwCxdeQjRUB0La_FPd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s one final step before you move on. You need to enable the Google+ API in the Developer Console.&lt;/p&gt;

&lt;p&gt;From the Dashboard add an API and select Google+.&lt;/p&gt;

&lt;p&gt;Now you should be set to go. Give it a try!&lt;/p&gt;

&lt;p&gt;Start IdentityServer and navigate to https://localhost:5443/grants. Log in using your Google account, or use one of the pre-configured demo users (i.e. &lt;code class=&quot;highlighter-rouge&quot;&gt;bob&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;alice&lt;/code&gt;, with a password of &lt;code class=&quot;highlighter-rouge&quot;&gt;password&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Brilliant! We’ve now got an API, and a basic IdentityServer running, with support for Google SignIn.&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 12 Nov 2018 00:00:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part3.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part3.html</guid>
        
        
      </item>
    
      <item>
        <title>Securing a Vue.js app and API with IdentityServer - Part 2</title>
        <description>&lt;p&gt;This is part 2 of a series showing you how to secure a Vue.js app with IdentityServer and call an ASP.NET Core Web API.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part1.html&quot;&gt;Part 1 - Overview and Solution Structure&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Part 2 - Creating and Configuring your IdentityServer (this post)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part4.html&quot;&gt;Part 4 - Creating and securing an ASP.NET Core Web API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part5.html&quot;&gt;Part 5 - Creating the Vue.js client&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part6.html&quot;&gt;Part 6 - Calling an HTTP API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part7.html&quot;&gt;Part 7 - Securing a router view in Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part8.html&quot;&gt;Part 8 - Calling a secured API from Vue.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part9.html&quot;&gt;Part 9 - Refreshing identity tokens with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;You can find the source code for this post series on &lt;a href=&quot;https://github.com/rbanks54/vue-and-identityserver&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;creating-and-configuring-your-identity-server&quot;&gt;Creating and configuring your Identity Server&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://identityserver4.readthedocs.io/en/release/&quot;&gt;IdentityServer&lt;/a&gt; is an open-source OpenID Connect and OAuth 2 framework. It’s not an out-of-the-box solution. It means it’s highly flexible, but that it also requires some extra effort from us to get it working.&lt;/p&gt;

&lt;p&gt;Thankfully, the IdentityServer team has provided some immensely useful Quickstart templates to help people like you and me to get up and running quickly. Handy!&lt;/p&gt;

&lt;p&gt;Start by cloning the repository at https://github.com/IdentityServer/IdentityServer4.Samples and then copy the &lt;code class=&quot;highlighter-rouge&quot;&gt;QuickstartIdentityServer&lt;/code&gt; folder from &lt;code class=&quot;highlighter-rouge&quot;&gt;Quickstarts/7_JavaScriptClient/src/QuickstartIdentityServer/&lt;/code&gt; into your solution root.&lt;/p&gt;

&lt;p&gt;In Visual Studio, add an existing project to  your solution and reference the Quickstart folder you just created.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/adding_identityserver.png&quot; alt=&quot;adding the IdentityServer Quickstart&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The IdentityServer Quickstart projects will listen on port 5000 using HTTP, not HTTPS, by default. Port 5000 will clash with the port we’re using for our web API application and we want secured communications so we need to adjust some properties.&lt;/p&gt;

&lt;p&gt;In the project properties page, change the Debug profile to use HTTPS on a different port number. Personally, I prefer to use Kestrel for local development and I don’t like the browser being auto-launched, so I’ve set my properties page as follows:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/2018-11/identityserver_property_page.png&quot; alt=&quot;IdentityServer property page&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You can adjust your configuration to suit your personal preferences. Just keep in mind that I’ve configured IdentityServer to run on https://localhost:5443.&lt;/p&gt;

&lt;p&gt;If, like me, you use Kestrel to run your app then you’ll want to quickly upgrade the Quickstart from .NET Core 2.0 to .NET Core 2.1.&lt;/p&gt;

&lt;p&gt;Doing so avoids the need to manually configure HTTPS support. You’ll only need to change the NuGet reference from &lt;code class=&quot;highlighter-rouge&quot;&gt;Microsoft.AspNetCore.All&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;Microsoft.AspNetCore.App&lt;/code&gt; and you’ll be set to continue.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Quickstart code stores everything in memory and is a long way from being a production-ready identity solution. For the purposes of this blog series, we’re going to leave most of it as-is.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;client-configuration&quot;&gt;Client Configuration&lt;/h3&gt;

&lt;p&gt;In IdentityServer &lt;em&gt;“clients”&lt;/em&gt; are the client applications connecting that want to connect to a secured resource. Our Vue.js application will be one of those clients applications and will use the &lt;code class=&quot;highlighter-rouge&quot;&gt;Implicit&lt;/code&gt; grant flow to authenticate.&lt;/p&gt;

&lt;p&gt;Firstly, find the Quickstart’s JavaScript client configuration in &lt;code class=&quot;highlighter-rouge&quot;&gt;Config.cs&lt;/code&gt; (you should see it at &lt;strong&gt;line 88&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Recall that our web application is going to be running on port 5000? When IdentityServer authenticates a person it will make a callback request to the client to complete the sign in process.&lt;/p&gt;

&lt;p&gt;We need to tell IdentityServer the URI of this callback endpoint. We’ll also adjust the ClientName so that the sign-in process looks a little nicer in the UI.&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// JavaScript Client&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ClientId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ClientName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;VueApi JavaScript Client&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AllowedGrantTypes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GrantTypes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Implicit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AllowAccessTokensViaBrowser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;RedirectUris&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://localhost:5000/callback&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;PostLogoutRedirectUris&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://localhost:5000/&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;AllowedCorsOrigins&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;https://localhost:5000&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;AllowedScopes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;IdentityServerConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StandardScopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OpenId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;IdentityServerConstants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StandardScopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s&quot;&gt;&quot;api1&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Redirect URI will be a route we create (later) in our Vue.js app and is where we’ll handle the IdentityServer callback.&lt;/p&gt;

&lt;p&gt;P.S. In case you missed it, we also changed from &lt;code class=&quot;highlighter-rouge&quot;&gt;http://&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;https://&lt;/code&gt; in the URIs other URIs on the page.&lt;/p&gt;

&lt;p&gt;Check your code compiles and that your IdentityServer starts. You won’t be able to do too much just yet, but you should be able to log in using the preconfigured users &lt;code class=&quot;highlighter-rouge&quot;&gt;Bob&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Alice&lt;/code&gt;, each with a password of &lt;code class=&quot;highlighter-rouge&quot;&gt;Password&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One final note; I prefer using &lt;code class=&quot;highlighter-rouge&quot;&gt;dotnet watch run&lt;/code&gt; from the specific project folders (not the solution root) to run both the IdentityServer and API applications. If you prefer running from Visual Studio, don’t forget to change the startup project or to manually start the specific projects as we go through the series.&lt;/p&gt;

&lt;p&gt;Up Next: &lt;a href=&quot;/2018/11/securing-vue-with-identityserver-part3.html&quot;&gt;Part 3 - Adding Google Authentication to IdentityServer&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Sun, 11 Nov 2018 23:30:00 +0000</pubDate>
        <link>https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part2.html</link>
        <guid isPermaLink="true">https://www.richard-banks.org/2018/11/securing-vue-with-identityserver-part2.html</guid>
        
        
      </item>
    
  </channel>
</rss>
