Home

Awesome

Fauna Auth skeleton

This repository contains unofficial patterns, sample code, or tools to help developers build more effectively with [Fauna][fauna]. All [Fauna Labs][fauna-labs] repositories are provided “as-is” and without support. By using this repository or its contents, you agree that this repository may never be officially supported and moved to the [Fauna organization][fauna-organization].


What does it do?

This repository contains ideas and implementations for authentication with Fauna in the client-serverless scenario. Prior to the release of this skeleton, Fauna Blueprints were released which implement several aspects of authentication. These blueprints contain the pure Fauna logic (in the form of User Defined Functions) and resources in a format that can quickly be deployed with the Fauna Schema Migrate tool. Blueprints do not contain a frontend or backend since everyone has different preferences, to keep things understandable and easy to deploy, they only focus on Fauna. Of course, when it comes to authentication, many questions are answered in the frontend and backend. How do we wire everything up with a backend and frontend? What do we call from the frontend and what do we call from the backend? Where do we store tokens? This skeleton uses the blueprints and implements an example approach with a React frontend an NodeJS backend. You can use it to learn how to implement login, register, logout, refresh, silent refresh, email verification, email/password validation, password resets etc with Fauna.

Architecture

Most authentication calls flow from the frontend to the backend as in a regular three-tier application. This allows us to use httpOnly cookies to store refresh tokens and implement email verification logic. Some calls like password changes based on your old password (when you are logged in) or password changes based on a password reset token received by email can be done directly and therefore bypass the backend. Once you are authenticated, the skeleton retrieved data directly from Fauna by using a short-lived access token. This allows us to get the best of both worlds, secure access yet faster (lower latency) access to our data and less strain on our backend. Regardless of whether calls flow through the backend, the bulk of the logic is implemented entirely in Fauna using the FQL language.

flows

If we simplify it we can perceive the way our application behaves as a state machine. We start off operating in three-tier modus where calls flow through the backend. Once the user is authenticated, the client takes a more central role and directly interacts with Fauna via a short-lived access token. At the same time the client's access token is kept valid via silent refreshes. We could say that after authentication, we move to a client-serverless modus.

state

Client-serverless

This pattern exemplifies how client-serverless is not necessarily an all-in but rather an extra tool in your belt. In some cases it makes a lot of sense to go through a backen , in other cases you can opt to skip the backend. When to bypass the backend and when not to is a question that might come up when applying this approach. For each Fauna access, ask yourself two things:

If the answer to both questions is true, skipping the backend altogether for that specific call is an option.

Which blueprints are used in this skeleton?

The following blueprints are used by dropping the resources into the fauna folder. Most of them are unmodified but some are slightly tailored towards the skeleton and configurable values were replaced by values which are stored in Fauna.

Setup:

Npm install

There are three main folders:

Running npm install in the root folder should install all dependencies (including in the backend/frontend via postinstall), if something goes wrong, run npm install in the backend and frontend separately as well.

Migrate

Grab a Fauna Admin key and export it

export FAUNA_ADMIN_KEY=<your key>

Or keep it at the ready to insert when the Fauna Schema Migrate tool asks for it. Run the following command to apply all migrations.

npx fauna-schema-migrate apply all 

Or use the interactive tool and apply them one by one via npx fauna-schema-migrate run

Seed Data

To provide you with some data to explore the skeleton you can paste the following data in your fauna dashboard shell.

  1. Dinosaurs which serve as the data:
Do(
  Create(Collection('dinos'), {
    data: {
      name: 'Skinny Dino',
      icon: 'skinny_dino.png',
      rarity: 'exotic'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Metal Dino',
      icon: 'metal_dino.png',
      rarity: 'common'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Flower Dino',
      icon: 'flower_dino.png',
      rarity: 'rare'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Grumpy Dino',
      icon: 'grumpy_dino.png',
      rarity: 'legendary'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Old Gentleman Dino',
      icon: 'old_gentleman_dino.png',
      rarity: 'legendary'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Old Lady Dino',
      icon: 'old_lady_dino.png',
      rarity: 'epic'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Sitting Dino',
      icon: 'sitting_dino.png',
      rarity: 'common'
    }
  }),
  Create(Collection('dinos'), {
    data: {
      name: 'Sleeping Dino',
      icon: 'sleeping_dino.png',
      rarity: 'uncommon'
    }
  })
)
  1. Create two users.

    with the same password: 'testtest'

Do(
  Create(Collection('accounts'), {
    data: {
      email: 'normal@test.com',
      type: 'normal',
      verified: true
    },
    credentials: {
      password: 'testtest'
    }
  }),
  Create(Collection('accounts'), {
    data: {
      email: 'admin@test.com',
      type: 'admin',
      verified: true
    },
    credentials: {
      password: 'testtest'
    }
  })
)

Configure backend environment variables

The backend contains a .env.example file which you can copy.

cp backend/.env.example backend/.env

The most important parts in there are the bootstrap key and session secret.

The other Fauna variables like domain and scheme are there in case you want to connect to another environment then the default Fauna production environment (e.g. preview or a local docker setup). Finally, to send emails we use Mailtrap. Mailtrap is a fake email sender which allows you to easily test email flows without going through the thorough verification steps that real email services require.

You can find the Mailtrap credentials once you have a mailtrap.io account and created a mailtrap project in the SMTP settings of the project. If you prefer not to configure this, you can't get emails for verification or password resets but can still run the application.

Configure frontend environment variables

The frontend has a similar example file.

cp frontend/.env.example frontend/.env

It contains similar helper env variables in case you want to use a different Fauna environment and contains the REACT_APP_LOCAL___PUBLIC_BOOTSTRAP_KEY variable. Set this variable to a Fauna key with role 'frontend_public_role' which should also be available once you have loaded the schema with the FSM tool. (see 'Migrate' chapter)

Run

Run backend

npm run start_backend

Run frontend

npm run start_frontend

app

And if everything goes right, you will be greeted by the two dinosaurs which can be accessed by the frontend key you have configured and can register/login to get access to more dinosaurs.