Getting set up with Fauna, Remix.run, Auth0, and Cloudflare Workers
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
- Nodejs 16.7.0 or higher for the cloudflare worker dev environment
- A faunadb account, database and a collection (called "Todos" if you want to use this skeleton's code)
- An auth0 account and tenant
- Cloudflare account and the wrangler cli installed
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, scope
s 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