<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: xnoɹǝʃ uɐıɹq</title>
    <description>The latest articles on DEV Community by xnoɹǝʃ uɐıɹq (@brianleroux).</description>
    <link>https://dev.to/brianleroux</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30804%2Fc6d7274e-c404-4652-ae78-a4b6ddf7e295.jpg</url>
      <title>DEV Community: xnoɹǝʃ uɐıɹq</title>
      <link>https://dev.to/brianleroux</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/brianleroux"/>
    <language>en</language>
    <item>
      <title>Bulletproof Sessions with HttpOnly Cookies</title>
      <dc:creator>xnoɹǝʃ uɐıɹq</dc:creator>
      <pubDate>Mon, 06 Feb 2023 18:54:32 +0000</pubDate>
      <link>https://dev.to/begin/bulletproof-sessions-with-httponly-cookies-1kll</link>
      <guid>https://dev.to/begin/bulletproof-sessions-with-httponly-cookies-1kll</guid>
      <description>&lt;p&gt;When you visit a website, by default, it doesn't remember anything about you - it's like starting a new conversation every time you go to the website or even loading a new page on the same website you are already visiting. HTTP is a stateless protocol. What if you want the website to remember something about you? That's where sessions come in. Sessions are a way for a website to remember things about you, like if you're logged in or what's in your shopping cart.&lt;/p&gt;

&lt;p&gt;In this post, we'll talk about implementing sessions with HttpOnly cookies. HttpOnly cookies are the best way to ensure that your session data is safe and secure. We'll talk about why they're important and how to use them to create a session from scratch. It's a great way to add an extra layer of security to your website, and it's easier than you might think.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cookies
&lt;/h2&gt;

&lt;p&gt;A cookie is a small piece of data that a website stores on a user's computer. This data is then sent back to the website with every subsequent request, allowing the website to remember things like user preferences or login status. At the end of the day, a &lt;code&gt;Cookie&lt;/code&gt; is an HTTP request header, and writing a cookie is accomplished with the HTTP response header &lt;code&gt;set-cookie&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By default, cookies are sent back and forth between the browser and the server in plain text, making them vulnerable to theft by hackers. To help mitigate this risk, you can set the "HttpOnly" flag on a cookie. This flag tells the browser that the cookie should only be sent back to the server via HTTP requests and will not be accessible to client-side scripting such as JavaScript. In addition to HttpOnly, you can set the "Secure" flag on a cookie. This flag tells the browser that the cookie will only be sent over secure connections (i.e. HTTPS). The "Secure" flag helps to prevent the cookie from being intercepted by a hacker who may be listening in on an unsecured connection.&lt;/p&gt;

&lt;p&gt;When combined, HttpOnly and secure cookies provide a powerful defense against session hijacking. By keeping session data away from client-side scripts and encrypting it during transit, you can protect your users from a wide range of security threats. By taking the time to implement these security measures correctly, you'll be able to rest assured that your users' data is well-protected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a session with set-cookie
&lt;/h2&gt;

&lt;p&gt;Most frameworks, Enhance included, already bake in a session functionality you should use for most cases. That code is open source, has been audited by thousands, and has more affordances for better security. The following code is only for an example to learn about how sessions work.&lt;/p&gt;

&lt;h2&gt;
  
  
  A counter example
&lt;/h2&gt;

&lt;p&gt;A great use for session state is forms. Let's implement a bare bones counter to demonstrate.&lt;/p&gt;

&lt;p&gt;Start by creating a new Enhance project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create @enhance ./counter-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a basic custom element for debugging in &lt;code&gt;app/elements/my-debug.mjs&lt;/code&gt;. Sometimes folks are disturbed by the &lt;code&gt;.mjs&lt;/code&gt; but it really is not a big deal: this tells Node.js we’re using ES Modules instead of the older Common JS module system.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;debug&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;pre&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/pre&amp;gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Next, delete everything in &lt;code&gt;app/pages/index.html&lt;/code&gt; and replace it with a basic form, and our debugger element:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;/count&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;post&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;go&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;my-debug&amp;gt;&amp;lt;/my-debug&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Next, add some API routes to manage the data aspect of our counter. First, lets display the raw cookies in our debugger by creating an API route at &lt;code&gt;app/api/index.mjs&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;This code passes the HTTP request Cookies (&lt;code&gt;req.cookies&lt;/code&gt;) right back to the client as JSON. Enhance API routes that match Page routes will automatically populate &lt;code&gt;state&lt;/code&gt;. Nice!&lt;/p&gt;

&lt;p&gt;And finally, we’ll implement an HTTP POST handler for incrementing the count at &lt;code&gt;app/api/count.mjs&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// Max-Age wants seconds; this is five min in seconds&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;

 &lt;span class="c1"&gt;// we need to  parse the raw request cookie to find it&lt;/span&gt;
 &lt;span class="c1"&gt;// the cookie we care about is named 'count'&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

 &lt;span class="c1"&gt;// req.cookies looks like this: ['cookie1=value', 'cookie2=value']&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="c1"&gt;// cookies are HTTP headers, which are strings, so we need to cast value to Number&lt;/span&gt;
     &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
     &lt;span class="k"&gt;break&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;303&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;location&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;set-cookie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`count=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; Max-Age=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;; Secure; HttpOnly`&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;This is a lot of boilerplate you won’t need with built-in sessions but it is valuable for you to understand how things work so you can use an abstraction with confidence. We start out with some helpful default values. Max-Age is how long we want our cookie to live and count is the cookie value we’re interested in for this reduced example.&lt;/p&gt;

&lt;p&gt;As you may remember, the HTTP request has a helpful &lt;code&gt;req.cookies&lt;/code&gt; collection. But the cookies are key/value pairs separated by &lt;code&gt;=&lt;/code&gt; so we have to parse that data out. Once we find the cookie we’re looking for, on line 15, we have to cast it to a Number before incrementing it because cookies are headers and headers are a bunch of String values. With all that work done we’re ready to write the cookie on the response and redirect to the home page.&lt;/p&gt;

&lt;p&gt;Run the example with &lt;code&gt;npm start&lt;/code&gt;, and submit the form to watch your cookie increment. Pretty cool!&lt;/p&gt;

&lt;p&gt;While our session cookie is both &lt;code&gt;Secure&lt;/code&gt; and &lt;code&gt;HttpOnly&lt;/code&gt; you probably noticed the values are still in plain text. To further lock this down there are two strategies: signing and encrypting the cookie value for ‘stateless’ sessions and/or using database backed sessions and only storing a UUID in the cookie itself. Both techniques work fine, and even better can be combined.&lt;/p&gt;

&lt;p&gt;Database sessions are nice because you can control invalidation and aren’t limited by the size of cookie. Stateless sessions are nice because they don’t involve more moving parts like a database. Good frameworks, like Enhance, support both.&lt;/p&gt;

&lt;p&gt;In our next section we’ll look at the Enhance built-in session which does all the aforementioned work for you to build a very basic login flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a basic login flow on top of session
&lt;/h2&gt;

&lt;p&gt;Let's use the built-in session to implement a single-player login flow. No need for complicated authentication vendors for simple use cases like locking down a personal site or frankly even OAuth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with pages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;HTML-first&lt;/em&gt;&lt;/strong&gt; means starting with HTML pages! We have two routes: &lt;code&gt;app/pages/index.html&lt;/code&gt; and &lt;code&gt;app/pages/protected.html&lt;/code&gt; respectively.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-header&amp;gt;&amp;lt;/app-header&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;please-login&amp;gt;&amp;lt;/please-login&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;app-footer&amp;gt;&amp;lt;/app-footer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;







&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;app-header&amp;gt;&amp;lt;/app-header&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;sensitive-information&amp;gt;&amp;lt;/sensitive-information&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;app-footer&amp;gt;&amp;lt;/app-footer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Create custom elements
&lt;/h2&gt;

&lt;p&gt;Let's flesh out the implementation.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
   &amp;lt;h1&amp;gt;app header&amp;lt;/h1&amp;gt;
   &amp;lt;app-navigation&amp;gt;&amp;lt;/app-navigation&amp;gt;
 `&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;The header is pretty straightforward HTML code which itself embeds a custom element called &lt;code&gt;&amp;lt;app-navigation&amp;gt;&lt;/code&gt; we will look at that next:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;nav&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;a href=/ class=underline&amp;gt;home&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
 &lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;a href=/protected class=underline&amp;gt;protected&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
   &amp;lt;nav&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt; &lt;span class="nx"&gt;links&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/nav&amp;gt;
 `&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;This code is a little more interesting. We create an array of links to render in a standard &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt; element. If &lt;code&gt;state.store.authorized&lt;/code&gt; then the array will include a link to &lt;code&gt;/protected&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;plsLogin&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;form method=post action=/login&amp;gt;
   &amp;lt;input type=password name=password placeholder='enter secret'&amp;gt;
   &amp;lt;button&amp;gt;login&amp;lt;/button&amp;gt;
 &amp;lt;/form&amp;gt;`&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;form method=post action=/logout&amp;gt;
   &amp;lt;button&amp;gt;logout&amp;lt;/button&amp;gt;
 &amp;lt;/form&amp;gt;`&lt;/span&gt;


 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;section&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorized&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;logout&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;login&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;section&amp;gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;The &lt;code&gt;&amp;lt;please-login&amp;gt;&lt;/code&gt; element is similar, rendering a logout form if the &lt;code&gt;state.store.authorized&lt;/code&gt; and a login form if not authorized.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;protec&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;p&amp;gt;important information&amp;lt;/p&amp;gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;The final element &lt;code&gt;&amp;lt;sensitive-information&amp;gt;&lt;/code&gt; is just placeholder content we will protect from our backend API routes in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  API routes
&lt;/h2&gt;

&lt;p&gt;App business logic belongs in API route handlers. I like to start with GET handlers, but do what works for you.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;The index route handler grabs &lt;code&gt;req.session.authorized&lt;/code&gt; and ensures we get a boolean value from it even if the session value isn’t yet defined. We pass that to the &lt;code&gt;index.html&lt;/code&gt; page store by returning JSON.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;authorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;authorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;The protected page also looks at &lt;code&gt;req.session.authorized&lt;/code&gt; and immediately returns to the index page if it isn’t truthy. If it is truthy, we’re authorized, and can send that information to the &lt;code&gt;protected.html&lt;/code&gt; page store.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SECRET_PASSWORD&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/protected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authorized&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Seven lines of code! To implement authentication we hide the password in the backend in an environment variable. Env vars are a great place to store sensitive secrets like configuration information. You can set the environment variable locally by creating a &lt;code&gt;.env&lt;/code&gt; file with something like &lt;code&gt;SECRET_PASSWORD=mypassword&lt;/code&gt;.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;post&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;authorized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;Logging out by setting the session value authorized to &lt;code&gt;false&lt;/code&gt; and redirecting back home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;HttpOnly cookies are a great building block for better security by not leaking sensitive information to potentially insecure client browser environments. Enhance built-in session support makes building stateful flows a snap!&lt;/p&gt;

&lt;h2&gt;
  
  
  Further resources
&lt;/h2&gt;

&lt;p&gt;Full source for the raw &lt;code&gt;set-cookie&lt;/code&gt; example can be found here: &lt;a href="https://github.com/brianleroux/enhance-example-impl-session"&gt;https://github.com/brianleroux/enhance-example-impl-session&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full source code for the single player auth can be found here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/brianleroux/enhance-example-single-player-auth"&gt;https://github.com/brianleroux/enhance-example-single-player-auth&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See also:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://begin.com/blog/posts/2022-08-25-progressively-enhancing-form-submissions-with-web-components"&gt;https://begin.com/blog/posts/2022-08-25-progressively-enhancing-form-submissions-with-web-components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For real contrast, check out a way to do the same thing with AWS:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/security/reduce-risk-by-implementing-httponly-cookie-authentication-in-amazon-api-gateway/"&gt;https://aws.amazon.com/blogs/security/reduce-risk-by-implementing-httponly-cookie-authentication-in-amazon-api-gateway/&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Strangler except serverless with OpenJS Architect</title>
      <dc:creator>xnoɹǝʃ uɐıɹq</dc:creator>
      <pubDate>Mon, 23 Nov 2020 23:24:01 +0000</pubDate>
      <link>https://dev.to/brianleroux/strangler-except-serverless-with-openjs-architect-46m3</link>
      <guid>https://dev.to/brianleroux/strangler-except-serverless-with-openjs-architect-46m3</guid>
      <description>&lt;p&gt;The &lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html"&gt;strangler pattern&lt;/a&gt; is a technique for refactoring an application with new functionality by wrapping the old logic in new logic. In the modern era of web apps this technique has been adapted to intercept HTTP traffic in new application code, use feature flags to turn on and off new functionality and otherwise proxy everything back to the original domain. A few years back &lt;a href="https://twitter.com/ceejbot"&gt;Ceej&lt;/a&gt; pulled off an impressive &lt;a href="https://www.youtube.com/watch?v=OuhnwqbefVQ"&gt;migration from monolith to microservices&lt;/a&gt; using this technique at npm Inc. &lt;/p&gt;

&lt;h2&gt;
  
  
  Strangler but serverlessly
&lt;/h2&gt;

&lt;p&gt;By using AWS API Gateway we can do the same thing and even better setting this up takes roughly 30 seconds total. This enables your dev team to pick off routes one by one and make them stateless functions. Or maybe we want to host a static app elsewhere and build the dynamic backend with Lambda. &lt;/p&gt;

&lt;p&gt;Whatever the use case OpenJS Architect makes configuring this setup completely painless. Create an &lt;code&gt;app.arc&lt;/code&gt; file with the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app
myapp

@proxy
testing https://testing.brian.io
staging https://staging.brian.io
production https://brian.io

@http
post /graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run &lt;code&gt;arc init&lt;/code&gt; to generate the app. You can deploy it to your own AWS account with &lt;code&gt;arc deploy&lt;/code&gt; or setup &lt;a href="http://begin.com"&gt;Begin&lt;/a&gt; for CI/CD. This app will proxy all traffic to my brian.io domain except &lt;code&gt;post /graphql&lt;/code&gt; for my backend code. Eventually I will probably want to move the static assets onto S3 and manage my own CloudFront too …but this can now happen at any time!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>architect</category>
    </item>
    <item>
      <title>deno.town a web REPL for Deno</title>
      <dc:creator>xnoɹǝʃ uɐıɹq</dc:creator>
      <pubDate>Sun, 05 Jan 2020 05:00:50 +0000</pubDate>
      <link>https://dev.to/brianleroux/deno-town-a-web-repl-for-deno-5b20</link>
      <guid>https://dev.to/brianleroux/deno-town-a-web-repl-for-deno-5b20</guid>
      <description>&lt;p&gt;Deno is a new experimental JavaScript runtime. Get to know API with a web REPL playground with linting and code completion at &lt;a href="https://deno.town"&gt;Deno.town&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>deno</category>
      <category>repl</category>
    </item>
  </channel>
</rss>
