Javascript

How To Authenticate Your SolidJS Routes With Solid Router

Jerry Hogan
4 min read
How To Authenticate Your SolidJS Routes With Solid Router
This article was written over 18 months ago and may contain information that is out of date. Some content may still be relevant, but please refer to official documentation for the latest information.

In this post, we will talk about how we can authenticate our SolidJS route with Solid Router. By the end of this article, we will understand what authentication is, and how it is used to guard routes in SolidJS using the Solid Router.

Overview

Route authentication has been around for a while, and is now a fundamental part of many applications like Facebook, Gmail, and Instagram. At this point, it’s about as ubiquitous as entering a password into a phone. Authentication through route guards in SolidJS can be achieved in two different ways. The first that we are going to cover in this app is the use of a Solid Router. The second is provided by Solid Start, which is more like a folder-based routing. It is a meta-framework (a framework built on another framework). At its core, it's powered by SolidJS and Solid Router. This article assumes that you have already set up a SolidJS project, and will not walk through that part of the process. If you have not yet spun up a project, you can find tutorials and instructions at SolidJS.

What is Authentication?

Authentication is a process of verifying the identity of the user. It provides access control to check if the user is authenticated. Authentication enables organizations to keep their networks secure by permitting only authenticated users or processes to gain access to their protected resources which, in our case, is the route in the application.

To learn more about authentication, you can check out the following;

What is a route guard?

A route guard helps to prevent unauthenticated users from accessing certain routes/parts in an application. For example, an app lock on a mobile phone can be seen as a guard. You may be able to access the phone and some apps, but you can’t access other apps.

We can also use parental controls on the phone, internet, and so on as a type of guard. You can read more about route guard.

Get Started

If you haven't installed the Solid Router in your project, run the command below:


  # Using NPM
  npm i @SolidJS/router

  # Using PNPM
  pnpm i @SolidJS/router

  # Using yarn
  yarn add @SolidJS/router

Solid Router is a universal router for SolidJS which works whether you're rendering on the client or the server. It was inspired by and combines the paradigms of React Router and the Ember Router. To read more, check out Solid Router

Having installed @SolidJS/router, we will be creating the following files;

  • Home: src/pages/Home.jsx
  • Signin: src/pages/Signin.jsx
  • Pricing: src/pages/Pricing.jsx
  • RouteGuard: src/RouteGuard/index.jsx
  • Header: src/components/Header/index.jsx
  • Header styles: src/components/Header/Header.module.css

Terminologies

  • useNavigate: a library provided to us by SolidJS Router that is used to navigate.
  • createEffect: creates a listener, which calls it's first argument when attached signals change.
  • Outlet: serves as the children associated with RouteGuard wrapper
  • NavLink: used to navigate between pages just like a tag which takes a property href for the page route path.

Home page

Below is the code we will paste in our home page file. But if you already have a content for this, you don't have to change it.

import appstyles from '../App.module.css';
export default function Home() {
  return (
    <div class={appstyles.wrapper}>
      <h2>Home page here</h2>
      <p>You can see this because you are authenticated</p>
    </div>
  );
}

This is just a simple page component with a style imported at the top.

Signin page

This is the content of our sign in page, but if have a content already, that's fine. The most important contents are the logIn function and the createEffect.

import { useNavigate } from "@SolidJS/router";
import { createEffect } from "solid-js";
import appstyles from "../App.module.css";

export default function SignIn () {
  const navigate = useNavigate();
  const logIn = () => {
    sessionStorage.setItem('token', 'mytokenisawesome');
    navigate('/home', { replace: true });
  };

  createEffect(() => {
    if(sessionStorage.getItem('token')) {
      navigate('/home', { replace: true })
    }
  })
  return (
    <div class={appstyles.wrapper}>
      <h2>Sign In Page</h2>
      <p>You can see this because you are not authenticated</p>
      <button class={appstyles.login_btn} onClick={logIn}>Log In</button>
    </div>
  )
}

The logIn function will be called when the login button is clicked. When clicked, a hardcoded token is saved in the session storage. The user is then navigated to the home page, which by default, can only be accessed if the user has been authenticated. The createEffect ensures the authenticated user won't access the sign in page.

Pricing page

This is just another page which, in this project, represents another protected page that could only be accessed by an authenticated user.


import appstyles from "../App.module.css";

export default function Pricing() {
  return (
    <div class={appstyles.wrapper}>
      <h2>Pricing page here</h2>
      <p>You can see this because you are authenticated</p>
      <i>Here you can find all prices</i>
    </div>
  );
}

This is just a simple page component with a style imported at the top.

RouteGuard Component


import { Outlet, useNavigate } from "@SolidJS/router";
import { createEffect } from "solid-js";
import Header from "../components/Header";

export default function RouteGuard () {
  const navigate = useNavigate();
  const token = sessionStorage.getItem('token');

  createEffect(() => {
    if(!token) {
      navigate('/signin', { replace: true });
    }
  })

  return (
    <div>
      <Header />
      <Outlet />
    </div>
  )
}

This serves as the wrapper for routes you want to protect from unauthenticated users. If there is no token in the session storage, the user will be routed to the signin page.

Header component

If you already have the content for the header file, you don't have to change it. All you need is the logOut function.


import { NavLink, useNavigate } from "@SolidJS/router";
import styles from './Header.module.css';

export default function Header() {
  const navigate = useNavigate();

  const logOut = () => {
    sessionStorage.removeItem('token');
    navigate('/signin', { replace: true });
  }
  return (
    <div class={styles.container}>
      <h3>My SolidJS App</h3>
      <div class={styles.links}>
        <NavLink href="/home">
          Home
        </NavLink>
        <NavLink href="/pricing">
          Pricing
        </NavLink>
      </div>
      <button class={styles.logout_btn} onClick={logOut}>Log out</button>
    </div>
  );
}

Above, we have styles imported from the header CSS module, and we have a logOut function that is used to remove the token from the session storage and also navigate the user to the signin page.

Header styles

This is the style for the header component.

.container {
  padding: 0.5rem 1rem;
  background-color: rgb(34, 80, 130);
  color: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.links {
  color: #fff;
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: flex-end;
  gap: 1rem;
  font-size: 1rem;
  text-decoration: none;
  padding: 0 1.5rem;
  text-transform: uppercase;
}
.links a:link, a {
  color: #fff;
  text-decoration: none;
}

.logout_btn {
  padding: 0.5rem 0.86rem;
  background-color: #fff;
  color: rgba(255, 0, 0, 0.795);
  text-transform: uppercase;
  border: 0;
  outline: none;
  border-radius: 0.3rem;
  font-weight: 800;
  cursor: pointer;
  transition: background-color 0.2s ease-in-out;
}

.logout_btn:hover {
  background-color: rgb(239, 236, 236);
}

Updates for src/App.jsx

This file is where the route is managed, and where we grouped certain routes we wanna guard or protect from unauthenticated users.

import { Route, Routes } from '@SolidJS/router';
import Home from './pages/Home';
import SignIn from './pages/Signin';
import RouteGuard from './RouteGuard';
import Pricing from './pages/Pricing';

function App() {
  return (
    <Routes>
      <Route path="/signin" component={SignIn} />
      <Route path="/" component={RouteGuard}>
        <Route path="/home" component={Home} />
        <Route path="/pricing" component={Pricing} />
      </Route>
      <Route path="*" element={()=> <div>Page Not found!!!</div>} />
    </Routes>
  );
}

export default App;

Update for src/App.module.css


.login_btn {
  padding: 0.5rem 0.86rem;
  background-color: rgb(34, 80, 130);
  color: #fff;
  text-transform: uppercase;
  border: 0;
  outline: none;
  border-radius: 0.3rem;
  font-weight: 800;
  cursor: pointer;
  transition: background-color 0.2s ease-in-out;
}

.login_btn:hover {
  background-color: rgb(27, 64, 104);
}

.wrapper {
  padding: 1rem;
}

Updates for src/index.jsx

We have to update this file by wrapping our App with Router


/* @refresh reload */
import { render } from 'solid-js/web';
import { Router } from '@SolidJS/router';

import './index.css';
import App from './App';

render(() => (
  <Router>
    <App />
  </Router>
), document.getElementById('root'));

Update for src/index.css

a.active, a:active {
  text-decoration: underline !important;
  text-decoration-line: underline;
  text-decoration-style: wavy !important;
  text-decoration-color: rgba(255, 0, 0, 0.795) !important;
  text-underline-offset: 2px;
  text-decoration-thickness: from-font;
}

Conclusion

In this article, we were able to understand what authentication is, and how to create a route guard which is very important when trying to prevent certain users from accessing certain routes in our application. I hope we have been able to help you see the possibilities of making use of SolidJS and Solid Router to build a well-authenticated application. If you are having issues, you can check out the repo for SolidJS-route-guard. Don't forget that you can see, in detail, how this was maximized in one of This Dot's open source project starter.dev GitHub Showcases.

Happy coding!

About the author

Jerry Hogan

Jerry Hogan

Software Engineer

Passionate developer, super fan of Vue, a singer, writer and musician.

Keep reading

View all posts →

Understanding Effects In SolidJS

In SolidJS, effects are a fundamental concept that helps developers manage side effects and reactive dependencies within their applications. ...

Victor Umeh3 mins
SolidJS

Deep Dive Into How Signals Work In SolidJS

SolidJS and Qwik have shown the world the power of signals, and Angular is following suit. There’s no way around them, so let's see what they are, why one would use them, and how they work. Signal basics Signals are built using the observer pattern. In this pattern, a subject holds a list of observers who are subscribed to changes to the subject. Whenever the subject gets changed, all subscribers will receive a notification of the update. Typically through a registered callback method. Observers may push new changes to that subject or other subjects. Triggering another set of updates throughout the observers. From the above, you might have guessed that infinite loops are a big caveat with using the observer pattern. The same holds true for signals. The power of this pattern lies in the separation of concerns. Observers need to know little about the subject, except that it can change. Whichever actor is going to change the subject needs to know nothing about the observers. This makes it easy to build standalone services that know only about their domain. Signals in front end frameworks SolidJS brings the observer pattern to the table for front end frameworks through signals. Observers can be added to a signal through SolidJS’s concept of Effects (by using createEffect). Components within SolidJS can be seen as both an observer and a subject at the same time. The component subscribes to all signals that are used to render the components HTML. SolidJS’s rendering system, in turn, is subscribed to all components. Where the components act as subjects and SolidJS as an observer. So whenever a signal changes in a component, the component reacts by changing its output, which then triggers SolidJS to put the new output on the screen. Compare this to, for example, Vue or React. When a change to the state occurs, the new values are passed down the component hierarchy. Each component returns its new output, which can be either the same as the previous render or changed. The framework then compares this tree against what it already had, and determines which parts to update. This is more dependent on a single source of truth which needs to know about all the components in the system. Changes are loosely related to each other, and only by diffing the results can the next step be determined. This differs from SolidJS setup, which makes hard connections between changes and results, making what will get updated when a signal changes more straightforward. Writing our own Signals At first sight, signals seem magical, and one might be inclined to believe there are some compiler tricks going on. Yet it is all plain JavaScript, and in this article, we’ll demystify signals in order to use them to their full potential. We can create our own signals with pure JavaScript in less than 25 lines. Our simple version will not take objects or arrays as values as these are references in JavaScript and require special attention. Let's start with the interface. We want the signal creator, which is a function that returns a tuple with the first value being the getter and the second value the setter. The function accepts a value, which will be used as the initial value. This gives us: Note that, due to the fact that we created a new variable within the closure of our createSignal, the variable outside of its scope will not change. original on the last line will still be “1”. For simplicity, we’re going to leave objects and arrays out of the picture as these are references instead of scalar values, and need extra code to do the same thing. Now that we can read from and write to our signal (a.k.a. subject), we’ll need to add subscribers to it. Whenever the getter is called (i.e., the value is read), we want the originator of the call to be registered as an observer. Then, when the setter is called, we are going to loop over all subscribed observers, and notify them of the new value. Consider this fully working signal creator. We’re almost there. This snippet has a downside. It needs the observer to be passed as the argument to the getter. But we don’t want to deal with that. Our interface was to read signal(), and have some sort of magic register the observer for us. What comes next was an eye opener for me. I always believed there was some closure trick, or built in JavaScript function to retrieve parent closures. That would have been a fantastic way to get who called the getter function and register it as an observer. But JavaScript offers nothing to support us in this. Instead, a way more simple trick is used, and it is seemingly used in every major framework. Frameworks, among others, React and SolidJS, store the parent in a global variable. Because JavaScript is single threaded, it needs to execute all operations in order. It does a lot under the hood to get stuff like async to work. Clever developers have relied on this single threaded aspect by writing to a global variable, and reading from it in the next function. This gets a little abstract, so here’s a concrete example to demonstrate this setup. We do not need to worry about current getting overwritten, as the code will always execute in order. It’s safe to assume that it will have the value we expect it to have when the body of second is executed. Note that we clear the value in the body of first as we don’t want unwanted side effects by leaving the variable set. The Fully Working Signal Let’s add effects to our signals to complete the minimal signal minimal framework. With what we have learned in the previous section, we can create effects by Registering the effect callback (i.e., the observer) to our global variable current Calling the observer for the first time. This will read all signals it depends upon, therefore adding current to the observer list. Clearing current to prevent registering the observer to signals read in the future. For this, we remove the current argument from the getter, as this is now globally readable. And we can add the createEffect function. With this setup, we already have a working signal system. We can register effects and write out signals to trigger them. And there we have it! Working signals in just a couple of lines, no magic, no difficult JavaScript API. All just plain code. You can play around with the fully working example in this StackBlitz project. It has the signal setup as described, plus an example of stores. Run node index.js to see the result. This simple framework is only focused on showcasing signals. For demonstration purposes, it simply logs to the console. Frameworks like SolidJS have advanced effects and logic to get HTML rendering to work. If you’re interested in learning more about rendering, you can read Mark’s blog on how to create your own custom renderer in SolidJS Or put your newly learned skills to use in a new SolidJS project created with Starter.dev’s SolidJS and Tailwind starter!...

Maarten Bicknese5 mins
SolidJS

Introducing the New SolidJS and Tailwind CSS Starter Kit

We are delighted to announce our SolidJS + Tailwind Starter Kit on Starter.dev to help you build your next project with SolidJS and Tailwind CSS in no time. In this article, we will walk you through the kit, and how it is a great option for building your next project. This kit has been designed to build tiny and optimized web applications on both the JavaScript and CSS sides. It's very useful when the load time of your application's files is critical, like when the internet connection is slow or when you are building a mobile application for a targeted audience. Why SolidJS? SolidJS is a declarative, efficient, and flexible JavaScript library for building user interfaces. It lets you build web applications using a declarative API that you’re already familiar with. It’s a great alternative to React, Vue, and other popular JavaScript frameworks. It’s also a great choice for building static sites. The best feature of SolidJS is how tiny its build bundles are. It helps you ship less JavaScript to the browser. Why Tailwind CSS? Tailwind CSS is a utility first CSS framework for rapidly building custom user interfaces. It makes it easy to build complex UIs without having to write custom CSS. And the best feature of Tailwind CSS is how customizable it is. It helps you ship a very small CSS file to the browser. Starter Kit Features SolidJS A declarative, efficient, and flexible JavaScript library for building user interfaces. Tailwind CSS A utility first CSS framework for rapidly building custom user interfaces. Vite A build tool that aims to provide a faster and leaner development experience for modern web projects. Storybook An open source tool for developing UI components in isolation for React, Vue, and Angular. Vitest A fast and simple test runner for Vite. TypeScript A typed superset of JavaScript that compiles to plain JavaScript. Tailwind CSS Tailwind CSS makes it easy to build complex UIs without having to write custom CSS. The best feature of Tailwind CSS is how customizable it is. It helps you ship a very small CSS file to the browser. Also, Tailwind CSS is great at scale, so you can add as many utilities as you want. Storybook Storybook is an open source tool for developing UI components in isolation for React, Vue, Angular, and others. It makes building stunning UIs organized and efficient. It also helps you build components faster, and reuse them in your projects. It also helps you document your components. This kit comes with Storybook pre configured. You can start using it right away. Why Vite? Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. It's a great alternative to Webpack. It's fast and easy to use. It also helps you ship less JavaScript to the browser. It's a great choice for building static sites. This kit comes with Vite pre configured. You can start using it right away. Testing This kit comes with Vitest pre configured. Vitest is a tool that is built with Vite in mind from the start, taking advantage of its improvements in DX, like its instant Hot Module Reload (HMR). This is Vitest, a blazing fast unit test framework powered by Vite. It's a great alternative to Jest. It's fast and easy to use. How to get started? Run npx @this dot/create starter to start a new project from one of the kits in the Starter CLI library. Select the SolidJS, Tailwind kit from the CLI library options Name your project cd into your project directory and install dependencies using the tool of your choice (npm, yarn or pnpm) Copy the contents of the .env.example file into a .env file When to use this kit? This kit is a great alternative to React and SCSS. It focuses on performance and developer experience by providing a fast and leaner development experience for modern web projects. It also helps you write less CSS, and less JavaScript. Options to scale the kit to fit your needs In this section, we will walk you through the options you have to scale the kit even further to fit your needs. We didn't want to add too many options to the kit in order to keep it simple and easy to use, but we also wanted to provide you with the ability to scale the kit. PWA PWA is a great way to make your app available offline, and installable on mobile devices. It caches your app's assets to make it load faster. It also helps you build a great user experience, and increase your app's engagement by providing push notifications. If you want to add PWA support to the kit, you can use the PWA Vite Plugin to add PWA support to the kit. It covers the PWA integrations for Vite, and the ecosystem with zero configuration and is framework agnostic. Conclusion So as we discussed in this article this SolidJS starter kit is a great way to start your new SolidJS project because it has most of the tools you need installed and preconfigured for you from Storybook to Testing, and even the PWA configurations. We hope you enjoyed this article, and we hope you will enjoy using the kit. If you have any questions or suggestions, please feel free to reach out to us on Twitter or Contact form....

Mark Shenouda4 mins
SolidJSTailwind CSS

How to Create Your Own Custom Renderer in SolidJS

Intro In this article, we will explore what custom renderers are, the problem they solve, and how SolidJS has created a custom renderer that is quite unique because of its simplicity and ease of use. We will also learn how to create a custom renderer in SolidJS, and how to use it in our applications. Custom renderers have a long history with all the major frameworks in the market like Renderer2 in Angular, createRenderer in Vue, and React Reconciler in React. They are used to build awesome technologies and mind blowing libraries. SolidJS recently added the ability to create a custom renderer with Solid Universal Renderer. Note: We also have a great article about How to create a custom renderer for React that you can check out! Custom Renderers in SolidJS To better understand how custom renderers in SolidJS work, we have to understand it first in React and Vue (VDOM frameworks). In React, the library itself (React.js) doesn’t know anything about the DOM. It doesn’t understand what a div or h1 means. React converts all of the components into a JavaScript object that represents the UI in the memory (Virtual DOM), and then update the related nodes when the state changes in specific components. That’s it! This is how React and Vue work under the hood. The React Renderer (which is a different package called “react dom”) then works on rendering this Virtual DOM on the screen, and updates it when it receives updates from React.js. The same thing happens in Vue. From here, the custom renderers have come to live. You aren’t limited to using only the official Renderer for the framework, but you can also build your own.. We will learn more about them in the proceeding sections. But for now, you just need to know that there is no virtual DOM in SolidJS. But it modifies directly on the DOM. This is the only difference between the Custom Renderers in SolidJS and React or Vue. Real world Custom Renderers In this section, I’ll show you the most popular custom renderers that are used in many production applications in different frameworks. One of the most popular custom renderers in the industry is React Native (yes, it’s a React custom renderer for Android and iOS platforms). React three fiber is one of the most famous examples of React Reconciler in production. It converts the JSX VDOM to WebGL graphics. React pdf is a React renderer for creating PDF files on the browser and server. TroisJS is a Vue custom renderer for Three.js and WebGL. There are many, many more examples. HTML Nodes Everything you see on the screen in the web browser is a node; the HTML element is a node, the attribute of that HTML element is a node, for example: Also, the text between and opening and closing tags of this HTML element is a node: Let’s code a SolidJS custom renderer The process is going to be similar to React, but SolidJS Universal is even easier than React Reconciler because it has fewer options. Create a new file to write our renderer and import the createRenderer from SolidJS universal: Second, let’s create an empty renderer: Renderer Options Let’s break all of these options down in detail: createElement This option is responsible for handling the creation of a new element node. It takes only one parameter which is the element type and it could be something like h1, p, divetc And here we can play with the JSX elements for fun. For example, we can add our custom elements like: Technically, there is no HTML component called customLikeButton. But here in this option, we can resolve this type as we desire. createTextNode This option is responsible for handling creating a new text node. It takes only one parameter which is the text itself. replaceText This option is responsible for handling updating the text node when it gets updates. It takes two parameters; the actual text node that has been updated, and the new text. insertNode This option is responsible for inserting or injecting a new node in the UI and the DOM. It takes three parameters, the parent node, the node itself, and a reference node (anchor) in the parent node. removeNode This option is responsible for removing a node from the DOM. It takes two parameters, the parent node, and the node which needs to be removed setProperty This one is a little bit more complicated than the previous ones because it handles more categories. It is responsible for handling the attributes or properties of the element such as the classNames, style, and events like onClick and onSubmit. isTextNode This option is used internally to determine if this node is a text node or not. Note: the node.type in the line above is a pure JavaScript code. In JavaScript nodes have 12 types with 12 numbers each representing a type. For example, 1 represents an element node, and 2 represents an attribute node. For more info see the HTML DOM Element nodeType on W3Schools and Node.nodeType Web APIs MDN. getParentNode This option is being used internally in SolidJS renderer to get the parent node of a given node. getFirstChild This option is being used internally in SolidJS renderer to get the first node of a given parent node. getNextSibling This option is being used internally in SolidJS renderer to get the next node of a given node in the DOM tree. Renderer method There are a lot of methods for this renderer, but the most important one is render which we will replace the SolidJS web one with. There are additional methods available: effect memo createComponent createElement createTextNode insertNode insert spread setProp mergeProps The performance of SolidJS Universal Renderer Ryan Carniato, the creator of SolidJS, created a test on the SolidJS Universal Renderer in his stream of Benchmarking and Custom Renderers on his YouTube channel, and it was pretty interesting. It wasn’t much slower than the SolidJS web renderer at only a few milliseconds slower. To test it, you can use the js framework benchmark repo, which is an amazing tool you can use to compare the performance of different JavaScript frameworks. Conclusion In this article, we learned about the custom renderers in SolidJS and how to create one. We also learned about the performance of SolidJS Universal Renderer and how it compares to the SolidJS web renderer. I hope you enjoyed this article and learned something new. For more SolidJS resources, check out our solidjs.framework.dev where you can find all cool courses, tutorials, and libraries for SolidJS. Also you can create your next SolidJS project, try our SolidJS starter kit from Starter.dev it has a lot of tools pre configured for you. If you have any questions or suggestions, please feel free to send them to us or reach out to us on Twitter....

Mark Shenouda5 mins
Solid RouterSolidJS