Integrating Auth0 with Sapper

Sat, 28th Mar 2020
< More Articles

Add authentication in 5 minutes.

After examining a few other applications and being unhappy that all the routing protection was done in the client-side, I was surprised after reading the Auth0 node docs that a (very basic) Auth0 integration can be made in as few as 10 lines.

It's worth noting that this is a very early integration, I've not worried about token refresh or route protection yet, I'll follow up this post with some information about that.

This integration will handle your basic login/logout flow and populate the session store with your user information, so that you can use it *anywhere* in your app - serverside, clientside, preload, you name it.

You will need to add a link somewhere on your app to /login to kick auth off the authentication process. The basic steps are as follows.

Switch to express (since Auth0 uses express not Polka)

I've been told that this part can use Polka if you implement a very light API method which the Auth0 node SDK looks for. For the purposes of this article however, I'll stick with expressjs since it's what the SDK expects.

Install express and the SDK. You want to install these as runtime (production) dependencies not dev dependencies as you normally do in Sapper, since you really don't want to bundle express:

npm install --save express express-openid-connect

You can then swap out Polka for Express, and import the Auth0 middleware:

Add in the Auth0 middleware with your config

import express from 'express'
import { auth } from 'express-openid-connect'

express() // used to say polka()

// and after the compression + sirv middleware, but before sapper.middleware

auth({
  required: false,
  auth0Logout: true,
  baseURL: 'http://localhost:3000',
  issuerBaseURL: 'https://your-hosted-url.auth0.com',
  clientID: 'your-client-id',
  appSessionSecret: 'your-session-secret'
})

Wrap the sapper middleware so you can access `req`

The Sapper middleware is greedy, because it handles routing for your app. What this means is that the moment it is initialised, it steals all the control over routing from other middlewares, meaning Auth0 can't add it's /login and /logout routes.

We can prevent this behaviour by wrapping it and then passing the request sent to our wrapper, to it. This is the same technique I use in https://github.com/beyonk-adventures/sapper-rbac .

You then populate the session in the middleware, using the data we received from Auth0.

(req, res, next) => { // middleware signature
  return sapper.middleware({
    session: () => {
      // populate the session with Auth0's auth information
      return {
        isAuthenticated: req.isAuthenticated(),
        user: req.openid.user
      }
    }
  })(req, res, next) // call the sapper middleware, passing it what was passed to us.
}

So how does this look in practice?

Add a link to your site which hits /login - or alternatively, just visit https://localhost:3000/login - if you've set everything up correctly, you should see the Auth0 login page. Once you log in you'll be redirected back to your app, as a logged in user.

Want to see who you are logged in as?

<pre>
  {$session.user}
</pre>

<script>
import { stores } from '@sapper/app'

const { session } = stores()
</script>

You can also use $session.isAuthenticated to determine if the current user is logged in or not.

Moving on

This little example is a great starter, but is not the full picture. A future article will discuss adding token refreshing to your app, to ensure that your user doesn't get logged out when the session expires. It's not critical, but if your app is anything more than a hobby app, you'll probably need it.