Snap for Beginners

Sample Chapter: Digestive Functors (Form Processing)

Authentication Snaplet

Basics

Adding to App Definition

Simply add _auth with a type of Snaplet (AuthManager App), we also need the Session Snaplet so we'll add that too. The heist snaplet is not strictly necessary, but we will use it to render splices from the Auth Snaplet.

Adding Auth to Routes

Handler Type

with auth takes a handler with a slightly different signature as an argument and returns a handler of the normal Handler App App () type. This means that the handle* functions in the example above are of this type:

We could rewrite the "/logout" handler to make this a bit more clear. We will add a new route "/hlogout", split out with auth handleLogout into it's own function (with type signature) and use the same handleLogout function to see the difference in handler types.

If we look at our App declaration in code/auth-app/src/Application.hs we can see that the new type signature for our handlers includes the type of our Auth Snaplet:

,_auth::Snaplet(AuthManagerApp)

Backends

Backends for the Authentication Snaplet are pluggable. Some of the current options include a flat JSON file and PostgreSQL.

JSON File

The default backend (given when you run snap init) is a flat JSON file. It is useful for examining how the system works, but should be replaced by the PostgreSQL backend or another database in production. One reason for this is that the users are stored in a flat file and this can cause issues.

Init with JSON

To initialize Auth with a JSON backend we will need to add the following import.

importSnap.Snaplet.Auth.Backends.JsonFile

Then we can use initJsonFileAuthManager to create the Auth backend inside of our app init code:

These instances wil need a {-# LANGUAGE FlexibleInstances #-} declaration at the top of Site.hs.

Restricted Routes

To restrict a route to only logged in users, we can use requireUser. First we'll add a route at /restricted that uses the auth snaplet:

("/restricted",withauthrestrictedHandler)

Then we'll write the handler with the auth snaplet in the type signature and a call to requireUser. requireUser takes a lensed auth snaplet value, such as auth, a handler to execute if there is no user logged in and a handler to execute if there is a user logged in.