In this tutorial, we'll go over web authentication using sessions. To get started, first download the starter project from GitHub here.

I typically don't like using starter projects, and prefer to show you everything from scratch, but web authentication is a bit more involved and requires a certain amount of (non auth related) setup just to demo, so for this one we have a starter project :)

Current Setup

Right now, the starter project has the following:

There is a User class and a Post class.

Each post belongs to one user

The User class conforms to PasswordAuthenticatable

There are routes/views for creating a post, registering a user, and viewing all posts

I am using a Postgres db

I have added the Authentication, Leaf, and PostgreSQL providers

Roadmap

The general flow for setting up session auth in our app is the following:

This allows us to use sessions within our app, and enables the session middleware that we will later use to retrieve our user for a given session.

Setup the Database (Postgres only)

If you are using Postgres, simply create the database for this app (defined in configure.swift, line 28) by running the following in terminal:

$ createdb webauth

Assign userId to Session

When a request comes into our server, we need to identify who made the request. To do so, we'll use sessions. The idea is that when a user logs in, we will store their id in a session cookie. Then, once logged in via username/password, that cookie will be sent from their browser to the server with each subsequent request.

With that in mind, the first thing we need to do is edit the login method, and make it assign the user's id to the session after successful login. To do so, replace the entire login method with the following:

This is our middleware that we'll use to verify whether or not a session contains a userId or not. If no value is sent, then we will throw a 403 Unauthorized error. We will need to apply this middleware to all routes we wish to protect that only a valid user can view.

Here, at 1 we create a group of routes that are going to be protected by our SessionAuthenticationMiddleware. And at 2, and 3 we protect the get and post routes for both showing the createPost page, and actually creating a post. We need to protect both, not just the route for showing the createPost page, because if someone were to find our route for actually creating a post (which can be easily done by looking at the HTML form), they could still otherwise create posts via a REST api call.

Start your server, and without logging in, go to /createPost, and you should receive a 403 Unauthorized response.

In UserController.swift, also change the route /me to be protected as well, like so:

Next, go to the createPost method. Currently, the userId is hardcoded (to make this compile). Now, let's use our Request extension to get the current user instead of hard coding. Replace the contents of the closure with the following:

At this point, you should be able to start your server and then login. After login, you will be redirected to a page that has your current username. You can then navigate to /createPost to create a post, and then /allPosts to view all posts.

The only thing missing is logout!

Logout

Log out is simple! We just need to set session()["userId"] to be nil. So, let's add a route to logout. In UserController.swift: