v0.21

authentication

introduction

dframework makes implementing authentication extremely simple. the global Auth facade provides a simple, unified api for managing user sessions and authentication state across your application.

configuration

authentication settings live in config/auth.js. by default, a single model authentication configuration points to User:

1// config/auth.js
2export default {
3 model: 'User'
4};

the session cookie name can be customized in config/app.js via sessionCookie or the SESSION_COOKIE environment variable (defaults to sid):

1// config/app.js
2export default {
3 sessionCookie: Env.value('SESSION_COOKIE', 'sid'),
4};

authenticating users

logging in

to log a user into your application, you may use the login method on the Auth facade. this method accepts the user model instance. you can also optionally pass additional session data as the second argument, and a boolean as the third argument to indicate if the session should be "permanent" (long lived).

NOTE

when a user logs in via `Auth.login()`, their id is securely stored and the session identifier is regenerated automatically to mitigate session fixation attacks.

1import { Hash } from 'dframework';
2import User from '../models/User.js';
3
4export async function authenticate(req, res) {
5 const user = await User.findByEmail('tarou@example.com');
6
7 if (user && await Hash.verify('secret', user.password)) {
8 // log the user in and set a long lived session cookie
9 await Auth.login(user, { role: 'admin' }, true);
10
11 return redirect('/dashboard');
12 }
13
14 return back('/login').withErrors({ email: 'invalid credentials' });
15}

logging out

to log the user out of the default guard, use the logout method. this clears the default guard's session key while preserving other active guard sessions.

1await Auth.logout();

checking authentication state

to determine if the current request is authenticated, use the check method. it returns true if the user is logged in.

1if (Auth.check()) {
2 // the user is logged in
3}

retrieving the authenticated user

you may access the authenticated user via the user method on the Auth facade. this returns the active user model instance, or null if the user is unauthenticated.

1const user = Auth.user();
2
3if (user) {
4 Log.info(`welcome back, ${user.name}`);
5}

retrieving user id

to quickly retrieve the authenticated user id without accessing properties manually, use the id method:

1const userId = Auth.id();

multi guard authentication

when your application needs independent authentication for multiple distinct entity types (for example, regular users and administrators), you can define guards in config/auth.js.

defining guards

guards are registered under the guards object in config/auth.js. each guard specifies its model and optional custom session key (which defaults to ${guardName}Id):

1// config/auth.js
2export default {
3 default: 'web',
4 guards: {
5 web: {
6 model: 'User',
7 sessionKey: 'userId'
8 },
9 admin: {
10 model: 'Admin',
11 sessionKey: 'adminId'
12 }
13 }
14};

using guards

to perform authentication actions on a specific guard, use the guard method on the Auth facade:

1// check if an admin is logged in
2if (Auth.guard('admin').check()) {
3 const admin = Auth.guard('admin').user();
4 const adminId = Auth.guard('admin').id();
5}
6
7// log in an admin (preserves active user sessions on other guards)
8await Auth.guard('admin').login(adminUser);
9
10// log out admin only
11await Auth.guard('admin').logout();

all guard reads (user(), check(), id()) are completely synchronous during requests.

flushing all guards

to completely clear all active guard logins and wipe session data in one call, use flush:

1await Auth.flush();

hashing

dframework provides a Hash facade which uses bcrypt for secure password hashing.

standard hashing

to hash a password, use the make method. it automatically generates a secure salt and applies 12 rounds of bcrypt hashing.

1import { Hash } from 'dframework';
2
3const hashedPassword = await Hash.make('my-password');

to verify a plain text password against a hash, use the verify method.

1if (await Hash.verify('plain-text', hashedPassword)) {
2 // passwords match
3}

deterministic fast hashing

occasionally, you may need to securely hash high entropy tokens (like api keys or personal access tokens) in a way that allows for exact database lookups. the fast method provides a deterministic sha256 hash using the server side APP_KEY as a pepper.

1// generating a token and saving its fast hash
2const token = Hash.random(40);
3const hashedToken = Hash.fast(token);
4
5// querying the database for the exact hashed token
6const record = await TokenModel.where('token', Hash.fast('provided-token')).first();