Coleman

A Rocket App with Auth0 Integration

In this post we’ll be walking through an example application I’ve sketched
out on GitHub. I threw this together because I didn’t see anything similar
for Rust, Rocket, and basic Auth0 integration.

We will go through the process step by step, from configuring Auth0 in their
management console, to building, configuring, and running our application.

Auth0 Configuration

This example uses what Auth0 calls a “Regular Web Application”. Create one of
these in the management console.

Create a new application, or use an existing one. Our application will need
these application settings values, so keep them handy:

Auth0 domain

Client ID

Client secret

Since our application will do an authentication handshake with Auth0, we must
also enter some configuration into the Auth0 management console itself. This
ensures Auth0 will only accept and call back to URLs we explicitly specify (it’s
all about security, after all).

First, add our localhost URL to the list of Allowed Callback URLs.

https://localhost:8000/login

Scroll down and save your changes.

You can also take note of the values in Advanced Settings > Endpoints. Auth0
sets these up for us, and our application will make use of these. Note that your
Auth0 domain is a component of these endpoints.

Install Rust (nightly)

You’ll need to install Rust, if you haven’t already.

Rust comes in two main flavors, stable and nightly. Since our project dependencies
(including Rocket) require bleeding-edge compiler features, we must use nightly.
Don’t let that scare you, managing versions of Rust is easy with rustup.

First, get rustup from https://rustup.rs/ and then use it to install
and use a nightly Rust compiler by default.

rustup default nightly

You should now have Rust and cargo, the official Rust build tool and package
manager. You can think of cargo as npm or pip, but for Rust.

These custom attributes are a bleeding-edge feature in Rust, and one of the
reasons we need the nightly compiler to use Rocket.

The Markup type and the excited!-looking html! macro are from maud, a
library that allows us to write dynamic templates as a DSL directly in our Rust
code. There isn’t much else to say about maud. The DSL is very HTML-like. Its
integration with Rocket is really great, and we don’t have to ship any static
HTML files. It’s all generated at compile time.

Rocket’s Request Guards

This is a tutorial about protecting parts of our site from unauthenticated
users. Rocket lets us do this with request guards. A request guard in
Rocket is simply a Rust type that implements the FromRequest trait. We can
then use these types in the function signature of our routes. The FromRequest
code, along with the url, will determine whether the route is served.

In our example, we have two handlers for the same "/" route, but they take
different parameters. Crucially, our User type is a request guard.

Since our User type is a request guard, the home function will only be
routed to if the associated request guard code succeeds.

Under the hood, our implementation of this request guard checks the user’s cookie
for a hashed jwt, and ensures that cookie value matches a hashed jwt in our database. If
any part of this fails, home will not be evaluated, and the request will be forwarded
to the next matching route. In our example, that’s the home_redirect function,
which immediately redirects to our login link.

Other frameworks use HTTP middleware for this sort of thing. In Rocket, we’re
encouraged to use request guards. This is a nice feature, because we could
potentially specify many request guards for a route, and adding or removing them
is a simpler process than refactoring middleware.

Rocket’s Managed State

Routes need to make use of shared resources, like database connections. Rocket
requires that we explicitly declare these dependencies with the manage method
at launch. Here is a snippet of code from our main function where we open a
sled database and bring it under Rocket’s
state management.

Note: an Arc in Rust is a smart pointer that lets us share resources between
threads. Our webserver is multi-threaded, so we must wrap our db handle with an Arc.

Once a resource is managed, we can bring it into the scope of any of our routes
by adding its type, wrapped with State, to the parameters of a handler function.
When Auth0 calls us back during an authentication handshake, we need access to
two bits of shared state: the database pointer and a settings object we construct
at launch.

Conclusion

If you’re new to Rust, jumping straight into web servers and authentication can
be daunting. I hope that I’ve provided something that builds, runs, and gets
you started. If anything is broken, or if you have better security recommendations
please open an issue.