Ross Hagan

Getting set up with Fauna, Remix.run, Auth0, and Cloudflare Workers

January 4, 2022

Here are some mildly tidied up notes and a skeleton example repository for building an application on the stack:

I hope the docs and code will offer some useful starter patterns and reference for getting up and running yourself.

Key Takeaways

  • User authentication with Auth0
  • Fauna documents (FQL based) with read permission determined based off the auth0 JWT's sub
  • Remix session backed by Cloudflare KV Store holding tokens with a secure session cookie on the client

What it's not

  • Deep security, use at your own risk and make sure you understand what's happening.
  • Great authorisation, only going so far as making sure a fauna document can be read by the user who created it.
  • Best practices, a completely new stack to the author, except auth0 in part, so your mileage will vary
  • Guaranteed complete, do take a look at the references below to fill gaps.
  • Offering logout - just haven't implemented it yet!

Setup

We're not going completely from scratch, or this would be a long article copy-pasting most of the docs already out there.

Where you should already be

Environment variables

Cloudflare workers use environment variables without process.env, so just constants that look like YOUR_BEAUTIFUL_ENV_VAR.

We've added some bindings into the skeleton repo at app/cloudflare-bindings.d.ts, and included them in the tsconfig.json's include list so our IDE doesn't scream and we get code completion on the key-value store.

The .env file is read in automatically by miniflare the local cloudflare worker environment, but you'll need to use the wrangler cli to define your worker's environment variables for a real deployment.

The .env.template file is worth having a read through as the shortest version of what you need that I could muster.

Read it? Fab, now copy it to a new .env file and keep filling it in as we go.

KV Store for session

We use KV store to keep the auth tokens (access, identity) out of the client.

Create a KV store using the wrangler cli:

wrangler kv:namespace create "AUTH_STORE"

You can call it anything, AUTH_STORE is just how it's named in this codebase. So if you need to rename it then remember to rename throughout the code too!

Connecting Auth0 to your application

You should have created an 'Application' in auth0, this project used the regular web application aiming for the auth code grant flow.

This new application will give you some of the values to complete the .env file.

For a local run, the application configuration should have your 'allowed callback url' set up.

By default miniflare will serve it at http://127.0.0.1:8787 if you haven't changed any defaults, so set your application configuration to have an allowed callback url of http://127.0.0.1:8787/auth should do the trick.

Connecting Auth0's JWT to FaunaDB resources

You'll need a database, a "Todos" collection, and to create an Access Provider in that database under security > providers.

The Issuer in your provider should look like:

https://<your tenant>.auth0.com/ - including the final /, it matters!

The JWKS endpoint should look like:

https://<your tenant>.auth0.com/.well-known/jwks.json

Double check your configuration from Auth0 by looking in the endpoints tab of your auth0 application's advanced settings.

Making the JWT the source of ownership for a fauna document

Do take a look at the auth0 fauna guide where this is mostly sourced from.

You'll need a new role, with create, read permissions on your Collection. (Write may not be necessary just yet, and we're not adding any write authorisation as part of this!)

This role can be created in your fauna dashboard in the database's security > roles. I've called the role "User".

In the new role's read custom code add:

Lambda(
  "ref",
  Equals(CurrentIdentity(), Select(["data", "owner"], Get(Var("ref"))))
)

With this, we're ensuring the CurrentIdentity (that is the sub value off your JWT) is equal to the owner for a succesful read.

Getting started developing

We've added tailwindcss via PostCSS so you'll need to npm run css:watch in a terminal to get live style updates, but don't take this as an exemplary implementation. It will compile styles out of the ./styles folder into the app/styles, which is in turn picked up by remix when it changes.

So now you can have the following commands running locally:

# in one tab (starts remix dev server)
npm run dev

# in another (starts miniflare server)
npm start

Open up http://127.0.0.1:8787 and you should be ready to go!

Deployment

Use wrangler to build and deploy your application to Cloudflare Workers, just remember you'll need to have used wrangler to put your secrets into cloudflare for a successful deployment.

npm run deploy

Next steps

Consider creating a wrapper function to perform authentication easily on any backend endpoint like loader functions. The skeleton code is written in a way that will mean calling authorize and throwing a redirect manually inside each loader/action.

That's good for explicit control, but might result in a lot of copy-pasted boilerplate. Try it and evolve it!

Also start thinking about the authorisation strategy you'll be using. There are a lot of options out there like Attribute Based Access Control, and Role Based Access Control. It may prove useful to have a similar authorisation wrapper function so you can configure and verify, for example, scopes expected to be present on the token or return a 403 Forbidden when they're not for each action or loader.

References

Remix Cloudflare Workers Docs
Remix Jokes App Tutorial - Authentication

Cloudflare's Auth0 Integration Guide

Fauna's Auth0 Guide
Auth0's Lighter Version of Fauna's Auth0 Guide