{"id":4566,"date":"2020-07-17T05:02:00","date_gmt":"2020-07-17T05:02:00","guid":{"rendered":"https:\/\/azoora.com\/blog\/?p=4566"},"modified":"2020-07-12T10:23:16","modified_gmt":"2020-07-12T10:23:16","slug":"tutorial-build-your-first-deno-app-with-authentication","status":"publish","type":"post","link":"https:\/\/azoora.com\/blog\/framework\/tutorial-build-your-first-deno-app-with-authentication\/","title":{"rendered":"Tutorial: Build Your First Deno App with Authentication"},"content":{"rendered":"\n<p>The creator of<strong> Node.js<\/strong>, <strong>Ryan Dahl<\/strong> has authored a <strong>new framework<\/strong> for designing web applications. He went back and fixed some mistakes he made in hindsight, taking advantage of new technologies that were not available at the time he originally wrote Node. The result is\u00a0<strong><a href=\"https:\/\/deno.land\/\">Deno<\/a>\u00a0<\/strong>(pronounced <strong>DEH-no<\/strong>), a framework for writing &#8220;Node-like&#8221; web applications in TypeScript. Here, We&#8217;ll help you will walk-through creating a basic web app with authentication.<\/p>\n\n\n\n<p>You can find almost all the information you need at the Deno website \u2014along with information on all the third-party libraries that are currently available for Deno. That is really the biggest drawback to the framework right now. It just hit version 1.0 on May 13th of 2020, so even though there are quite a few essential libraries, there are not nearly as many libraries as there are for Node. For those who are proficient in Node however, the transition to Deno should be pretty easy.<\/p>\n\n\n\n<p>You can find the installation instructions at&nbsp;<a href=\"https:\/\/deno.land\/#installation\">https:\/\/deno.land\/#installation<\/a>.<\/p>\n\n\n\n<h2 id=\"toc-create-your-deno-application\">1. Create Your Deno Application<\/h2>\n\n\n\n<p>There aren&#8217;t any basic scaffolding libraries that we could find, so We just started with an empty folder. In the application&#8217;s root folder, create a file called\u00a0<code>index.ts<\/code>\u00a0that will be the starting point of your Deno application. You&#8217;ll use\u00a0<a href=\"https:\/\/deno.land\/x\/opine\">Opine<\/a>, which is an Express clone for Deno to make building and routing easier.<\/p>\n\n\n\n<p>One thing that is different about Deno is that there are no package managers for bringing in third-party libraries. You do this by using the library&#8217;s full URL. Do that at the top of the&nbsp;<code>index.ts<\/code>&nbsp;file, then set up a basic web application.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { opine } from 'https:\/\/deno.land\/x\/opine@0.12.0\/mod.ts';\n\nconst app = opine();\n\napp.get('\/', (req, res) => {\n  res.send('Deno Sample');\n});\n\napp.listen(3000);\nconsole.log('running on port 3000');<\/code><\/pre>\n\n\n\n<p>You can then run this very basic application by going to the terminal in the application&#8217;s folder and entering:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>deno run -A index.ts<\/code><\/pre>\n\n\n\n<p>The&nbsp;<code>-A<\/code>&nbsp;is a shortcut for development purposes. Deno is completely locked down by default, so you&#8217;ll need to pass arguments to the&nbsp;<code>run<\/code>&nbsp;command to allow access like&nbsp;<code>--allow-net<\/code>&nbsp;to allow networking, and&nbsp;<code>--allow-read<\/code>&nbsp;to allow the application to read from the file system. The&nbsp;<code>-A<\/code>&nbsp;used here allows everything, effectively disabling all security. When you run this application and then go to&nbsp;<code>http:\/\/localhost:3000<\/code>&nbsp;you should be greeted with&nbsp;<strong>Deno Sample<\/strong>&nbsp;on a blank page.<\/p>\n\n\n\n<h2 id=\"toc-build-a-real-web-application-with-deno\">2. Build a Real Web Application with Deno<\/h2>\n\n\n\n<p>While this is a good first step, it&#8217;s not very useful. You&#8217;ll want to add some&nbsp;<em>real<\/em>&nbsp;functionality that&#8217;s a little more &#8220;real-world&#8221;, so change the&nbsp;<code>index.ts<\/code>&nbsp;file so that the contents are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { opine, serveStatic } from 'https:\/\/deno.land\/x\/opine@0.12.0\/mod.ts';\nimport { renderFileToString } from 'https:\/\/deno.land\/x\/dejs@0.7.0\/mod.ts';\nimport { join, dirname } from 'https:\/\/deno.land\/x\/opine@main\/deps.ts';\n\nimport { ensureAuthenticated } from '.\/middleware\/authmiddleware.ts';\nimport users from '.\/controllers\/usercontroller.ts';\nimport auth from '.\/controllers\/authcontroller.ts';\n\nconst app = opine();\nconst __dirname = dirname(import.meta.url);\n\napp.engine('.html', renderFileToString);\napp.use(serveStatic(join(__dirname, 'public')));\napp.set('view engine', 'html');\n\napp.get('\/', (req, res) => {\n  res.render('index', { title: 'Deno Sample' });\n});\n\napp.use('\/users', ensureAuthenticated, users);\napp.use('\/auth', auth)\n\napp.listen(3000);\nconsole.log('running on port 3000');<\/code><\/pre>\n\n\n\n<p>You&#8217;ll notice some more\u00a0<code>import<\/code>\u00a0statements which bring in some third-party libraries. Here, We&#8217;re using\u00a0<a href=\"https:\/\/deno.land\/x\/dejs\">dejs<\/a>\u00a0which is an EJS port for Deno. We&#8217;ve also included some utility classes from the Opine library for manipulating directory names. We&#8217;ll explain what the three files imported locally are in a moment. For now, just know that you&#8217;re importing them.<\/p>\n\n\n\n<p>The line below the instantiation of the\u00a0<code>opine()<\/code>\u00a0app creates a reference to the local directory. The three lines below use this to set the view engine to DEJS for processing the HTML-like files, similar to the way EJS does for Node. The next section has been changed slightly to render one of those HTML template files, and the last two lines bring in some external routes. One thing of note is that the\u00a0<code>\/users<\/code>\u00a0route has an <code>ensureAuthenticated()<\/code> middleware function. This will force users to log in before being allowed to visit the page. You&#8217;ll create that middleware shortly.<\/p>\n\n\n\n<h2 id=\"toc-fill-in-your-deno-application\">3. Fill In Your Deno Application<\/h2>\n\n\n\n<p>Now, you&#8217;ll want to create some of the missing pieces that you imported above. Start with the routes. Create a folder called&nbsp;<code>controllers<\/code>&nbsp;in the root of the application. Then add a&nbsp;<code>usercontroller.ts<\/code>&nbsp;file inside that folder with the following contents:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Router } from 'https:\/\/deno.land\/x\/opine@0.12.0\/mod.ts';\n\nconst users = new Router();\n\n\/\/ users routes\nusers.get('\/me', (req, res) => {\n  res.render('users\/me', { title: 'My Profile', user: res.app.locals.user });\n});\n\nexport default users;<\/code><\/pre>\n\n\n\n<p>This is a simple routing file. It gets the router from Opine and creates a new instance to hang routes from. Then there is code to add a route for&nbsp;<code>\/me<\/code>&nbsp;to render the HTML view in&nbsp;<code>users\/me<\/code>. The&nbsp;<code>render()<\/code>&nbsp;call also passes a title and the logged-in user to the page. This page will be protected so that there will always be a user to pass to the page.<\/p>\n\n\n\n<p>Next, create some views to show when the routes are hit. In the root folder, add a&nbsp;<code>views<\/code>&nbsp;folder. Inside that, create a&nbsp;<code>shared<\/code>&nbsp;folder and a&nbsp;<code>users<\/code>&nbsp;folder. In the&nbsp;<code>shared<\/code>&nbsp;folder create a&nbsp;<code>header.html<\/code>&nbsp;and&nbsp;<code>footer.html<\/code>&nbsp;file. In the&nbsp;<code>users<\/code>&nbsp;folder add a&nbsp;<code>me.html<\/code>&nbsp;file. Finally, in the&nbsp;<code>views<\/code>&nbsp;folder itself create an&nbsp;<code>index.html<\/code>&nbsp;file.<\/p>\n\n\n\n<p>These are pretty bare-bones, but it demonstrates how to create views that can be reused by other views. In the&nbsp;<code>shared\/header.html<\/code>&nbsp;file add the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!DOCTYPE html>\n&lt;html lang=\"en\">\n\n&lt;head>\n  &lt;meta charset=\"utf-8\">\n  &lt;meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n  &lt;title>&lt;%= title %>&lt;\/title>\n&lt;\/head>\n\n&lt;body><\/code><\/pre>\n\n\n\n<p>This outputs the top of an HTML page and injects the title into the page. Next, add the following to the&nbsp;<code>shared\/footer.html<\/code>&nbsp;file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;\/body>\n\n&lt;\/html><\/code><\/pre>\n\n\n\n<p>Now you can use those partials in the&nbsp;<code>index.html<\/code>&nbsp;file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;%- await include('views\/shared\/header.html', { title }); %>\n\n&lt;a href=\"\/users\/me\">My Profile&lt;\/a>\n\n&lt;%- await include('views\/shared\/footer.html'); %><\/code><\/pre>\n\n\n\n<p>This includes the footer and header partials and adds a link to the profile page. The contents of the&nbsp;<code>users\/me.html<\/code>&nbsp;file are:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;%- await include('views\/shared\/header.html', { title }); %>\n\n&lt;h1>My Profile&lt;\/h1>\n\n&lt;ul>\n&lt;% for(var p in user){ %>\n  &lt;li>&lt;strong>&lt;%= p %>: &lt;\/strong>&lt;%= user[p] %>&lt;\/li>\n&lt;% } %>\n&lt;\/ul>\n\n&lt;%- await include('views\/shared\/footer.html'); %><\/code><\/pre>\n\n\n\n<p>Again, this page includes the header and footer, and loops through the properties of the&nbsp;<code>user<\/code>&nbsp;object. Granted, it&#8217;s not a super-sexy profile page, but it will let you know that the authentication steps all worked.<\/p>\n\n\n\n<h2 id=\"toc-add-authentication-with-okta\">4. Add Authentication with Okta<\/h2>\n\n\n\n<p>If you don&#8217;t already have an Okta account, you can get a free developer account\u00a0<a href=\"https:\/\/developer.okta.com\/signup\">here<\/a>. Once you&#8217;ve signed into Okta, you&#8217;ll land on the dashboard. You&#8217;ll need to create an Okta app to take advantage of Okta as an Identity Provider for your project.<\/p>\n\n\n\n<p>Click on\u00a0<strong>Applications<\/strong>\u00a0in the menu, then\u00a0<strong>Add Application<\/strong>. This will take you to the application wizard. Choose\u00a0<strong>Web<\/strong>\u00a0for your platform, then click\u00a0<strong>Next<\/strong>. The next page is the\u00a0<strong>Application Settings<\/strong>\u00a0page. Give your application a name (We named our as <strong>DenoExample<\/strong>). Change all the URLs to use port\u00a0<code>3000<\/code>\u00a0instead of\u00a0<code>8080<\/code>, then change the\u00a0<strong>Login Redirect URIs<\/strong>\u00a0to\u00a0<code>http:\/\/localhost:3000\/auth\/callback<\/code>. This is a route you&#8217;ll be implementing shortly. Finally, click\u00a0<strong>Done<\/strong>\u00a0to finish creating the application in Okta.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-attachment-id=\"4567\" data-permalink=\"https:\/\/azoora.com\/blog\/framework\/tutorial-build-your-first-deno-app-with-authentication\/attachment\/add-authentication-with-okta\/#main\" data-orig-file=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta.png\" data-orig-size=\"800,1057\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"Add-Authentication-With-Okta\" data-image-description=\"\" data-medium-file=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta-227x300.png\" data-large-file=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta-775x1024.png\" loading=\"lazy\" width=\"775\" height=\"1024\" src=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta-775x1024.png\" alt=\"\" class=\"wp-image-4567\" srcset=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta-775x1024.png 775w, https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta-227x300.png 227w, https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta-768x1015.png 768w, https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Add-Authentication-With-Okta.png 800w\" sizes=\"(max-width: 775px) 100vw, 775px\" \/><\/figure>\n\n\n\n<p>Once you&#8217;re on the page for your newly-created application, make sure you&#8217;re on the&nbsp;<strong>General Settings<\/strong>&nbsp;tab and scroll to the bottom until you see a&nbsp;<strong>Client Credentials<\/strong>&nbsp;section. You&#8217;ll be using these values momentarily, so keep this window open.<\/p>\n\n\n\n<p>Back in your application, create a new file in the root of the application called&nbsp;<code>.env<\/code>. The contents of the file will be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>issuer=https:\/\/{yourOktaOrgUrl}\/oauth2\/default\nclientId={yourClientID}\nclientSecret={yourClientSecret}\nredirectUrl=http:\/\/localhost:3000\/auth\/callback\nstate=SuPeR-lOnG-sEcReT<\/code><\/pre>\n\n\n\n<p>Copy the Client ID and Client Secret from the\u00a0<strong>Client Credentials<\/strong>\u00a0section of your Okta app. Then go back to the dashboard and copy your Okta org URL from the right-hand side just below the menu.<\/p>\n\n\n\n<p>Now you&#8217;re ready to start talking to Okta for authentication. Unfortunately, We couldn&#8217;t find any OpenID Connect (OIDC) libraries to make authentication with OAuth 2.0 and OIDC easier than this, so you&#8217;ll have to create it by hand. However, this can be an awesome exercise to help understand how OAuth and OIDC work. In the root folder of your app, create a new folder called\u00a0<code>middleware<\/code>\u00a0and add a file called <code>authmiddleware.ts<\/code>. Then add this content:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { config } from 'https:\/\/deno.land\/x\/dotenv\/mod.ts';\n\nexport const ensureAuthenticated = async (req:any, res:any, next:any) => {\n  const user = req.app.locals.user;\n  if(!user){\n    const reqUrl = req.originalUrl;\n    const {issuer, clientId, redirectUrl, state} = config();\n    const authUrl = `${issuer}\/v1\/authorize?client_id=${clientId}&amp;response_type=code&amp;scope=openid%20email%20profile&amp;redirect_uri=${encodeURIComponent(redirectUrl)}&amp;state=${state}:${reqUrl}`;\n    res.location(authUrl).sendStatus(302);\n  }\n  next();\n}<\/code><\/pre>\n\n\n\n<p>First, bring a library for reading the\u00a0<code>.env<\/code>\u00a0file. The\u00a0<a href=\"https:\/\/deno.land\/x\/dotenv\">dotenv<\/a>\u00a0does this beautifully. Then you&#8217;ll implement the <code>ensureAuthenticated()<\/code> middleware that starts the first step of the authentication process. First, it checks to make sure the user isn&#8217;t already logged in. If they are, it just calls\u00a0<code>next()<\/code>\u00a0because there is nothing to do.<\/p>\n\n\n\n<p>If there isn&#8217;t a currently logged in user, it builds a URL made up of the issuer, clientId, redirectUrl, and state properties from the\u00a0<code>.env<\/code>\u00a0file. It makes a call to the\u00a0<code>\/v1\/authorize<\/code>\u00a0endpoint of the issuer&#8217;s URL. It then redirects to that URL. This is a login page hosted by Okta. Kind of like when you&#8217;re redirected to Google to log in with Google as the identity provider. The URL that it will call when login is done is the <code>http:\/\/localhost:3000\/auth\/callback<\/code> URL that&#8217;s in the\u00a0<code>.env<\/code>\u00a0file. We&#8217;ve also tagged the original URL that the user was going to when they were redirected to the\u00a0<code>state<\/code>\u00a0query parameter. This will make it easy to direct them back there once they&#8217;ve logged in.<\/p>\n\n\n\n<p>Next, you&#8217;ll need to implement the&nbsp;<code>auth\/callback<\/code>&nbsp;route to handle the result from the login page and exchange the authorization code that you&#8217;ll receive from Okta. Create a file called&nbsp;<code>authcontroller.ts<\/code>&nbsp;in the&nbsp;<code>controllers<\/code>&nbsp;folder with the contents:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { Router } from 'https:\/\/deno.land\/x\/opine@0.12.0\/mod.ts';\nimport { config } from \"https:\/\/deno.land\/x\/dotenv\/mod.ts\";\n\nconst auth = new Router();\n\n\/\/ users routes\nauth.get('\/callback', async (req, res) => {\n const { issuer, clientId, clientSecret, redirectUrl, state } = config();\n\n if (req.query.state.split(':')[0] !== state) {\n   res.send('State code does not match.').sendStatus(400);\n }\n\n const tokenUrl: string = `${issuer}\/v1\/token`;\n const code: string = req.query.code;\n\n const headers = new Headers();\n headers.append('Accept', 'application\/json');\n headers.append('Authorization', `Basic ${btoa(clientId + ':' + clientSecret)}`);\n headers.append('Content-Type', 'application\/x-www-form-urlencoded');\n\n const response = await fetch(tokenUrl, {\n   method: 'POST',\n   headers: headers,\n   body: `grant_type=authorization_code&amp;redirect_uri=${encodeURIComponent(redirectUrl)}&amp;code=${code}`\n });\n\n const data = await response.json();\n if (response.status !== 200) {\n   res.send(data);\n }\n const user = parseJwt(data.id_token);\n req.app.locals.user = user;\n req.app.locals.isAuthenticated = true;\n res.location(req.query.state.split(':')_[_1] || '\/').sendStatus(302);\n});\n\n\nfunction parseJwt (token:string) {\n  const base64Url = token.split('.')_[_1];\n  const base64 = base64Url.replace(\/-\/g, '+').replace(\/_\/g, '\/');\n  const jsonPayload = decodeURIComponent(atob(base64).split('').map(function(c) {\n      return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);\n  }).join(''));\n\n  return JSON.parse(jsonPayload);\n};\n\nexport default auth;<\/code><\/pre>\n\n\n\n<p>There is actually a lot less going on here than you might think. First, the imports bring in the\u00a0<code>Router<\/code>\u00a0from Opine and read in the\u00a0<code>.env<\/code>\u00a0file again. Then they instantiate the router like in the\u00a0<code>usercontroller.ts<\/code>\u00a0file. The next thing we did was deconstruct the config object to make it easier to use the values. Next, we checked the\u00a0<code>state<\/code>\u00a0query parameter to make sure it matches. This helps ensure that Okta is the one who sent the authorization code. Then the authorization code gets pulled off the query string with\u00a0<code>req.query.code<\/code>.<\/p>\n\n\n\n<p>What happens next is a call to the token endpoint. You&#8217;ll send the authorization code in a\u00a0<code>POST<\/code>\u00a0request to Okta to exchange for an ID Token. So, here we&#8217;ve built some headers for the request. The most important is the\u00a0<code>Authorization<\/code>\u00a0header that has a value of\u00a0<code>Basic {yourClientId}:{yourClientSecret}<\/code>\u00a0the client ID and secret are base64 encoded. Then the\u00a0<code>POST<\/code>\u00a0call is finally made to the token endpoint with those headers and a body with a\u00a0<code>grant_type<\/code>\u00a0of\u00a0<code>authorization_code<\/code> \u2014 the same redirect URL as before \u2014 and the authorization code we just received from Okta.<\/p>\n\n\n\n<p>The\u00a0<code>fetch()<\/code>\u00a0call returns a promise resolved with the\u00a0<code>then()<\/code>\u00a0function. We get the\u00a0<code>response<\/code>\u00a0object&#8217;s JSON value, make sure the call was successful, parse the\u00a0<code>id_token<\/code>\u00a0value with the\u00a0<code>parseJwt()<\/code>\u00a0function below and stick it into a local variable called\u00a0<code>user<\/code>. Finally, the user is sent to the URL they originally requested before being redirected for authentication.<\/p>\n\n\n\n<h2 id=\"toc-run-the-deno-application\">5. Run the Deno Application<\/h2>\n\n\n\n<p>You can now run the application from the terminal again with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>deno run -A index.ts<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-attachment-id=\"4569\" data-permalink=\"https:\/\/azoora.com\/blog\/framework\/tutorial-build-your-first-deno-app-with-authentication\/attachment\/my-profile\/#main\" data-orig-file=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile.png\" data-orig-size=\"800,576\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"My-Profile\" data-image-description=\"\" data-medium-file=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile-300x216.png\" data-large-file=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile.png\" loading=\"lazy\" width=\"800\" height=\"576\" src=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile.png\" alt=\"\" class=\"wp-image-4569\" srcset=\"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile.png 800w, https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile-300x216.png 300w, https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/My-Profile-768x553.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/figure>\n\n\n\n<p>Once it&#8217;s running you&#8217;ll be able to click on the profile link on the home page and will be redirected to Okta&#8217;s hosted login page. Once you&#8217;ve logged in, you&#8217;ll be directed back to the profile page and you&#8217;ll see your ID token&#8217;s properties displayed in a list.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The creator of Node.js, Ryan Dahl has authored a new framework for designing web applications. He went back and fixed some mistakes he made in hindsight, taking advantage of new technologies that were not available at the time he originally wrote Node. The result is\u00a0Deno\u00a0(pronounced DEH-no), a framework for writing &#8220;Node-like&#8221; web applications in TypeScript. [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":4568,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[102,145,7,62],"tags":[103,146,28,110],"jetpack_featured_media_url":"https:\/\/azoora.com\/blog\/wp-content\/uploads\/2020\/07\/Build-Your-First-Deno-App-With-Authentication.png","jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/p7FQPL-1bE","jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/posts\/4566"}],"collection":[{"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/comments?post=4566"}],"version-history":[{"count":1,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/posts\/4566\/revisions"}],"predecessor-version":[{"id":4570,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/posts\/4566\/revisions\/4570"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/media\/4568"}],"wp:attachment":[{"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/media?parent=4566"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/categories?post=4566"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/azoora.com\/blog\/wp-json\/wp\/v2\/tags?post=4566"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}