Skip to main content

Authentication

Formidable provides a starter authentication system for both session and jwt based applications. By default, session based authentication is enabled.

The session based authentication system enables the use of cookies, and stores the session data in memory, file or redis. While the jwt based authentication system enables the use of JWT tokens, and stores authentication data in the database.

You can find your application's authentication configuration in config/auth.imba.

Getting Started

Formidable will automatically enable authentication for you. Should you not want to use authentication in your application, you can disable it by removing Auth.routes! from the app/Resolvers/RouterServiceResolver.imba, this will disable all authentication routes.

Database Considerations

Its important to note that you will need to create a database for your application to use authentication. If a database has been created, head over to your .env file and config/database.imba config file to configure your database connection, once this is done, you can run:

node craftsman migrate:latest

This will create all the tables needed for authentication. users, password_resets and personal_access_tokens tables will be created.

Configure Client

The email and password routes require a client url to be configured. This url is prepended to the routes. To configure this url, head over to your .env and set the CLIENT_URL environment variable.

Actions

Login

Log a user in

POST http://localhost:3000/login
Content-Type: application/json

{
"email": "email-address",
"password": "password"
}

Logout

Log a user out

POST http://localhost:3000/logout

Register

Register a user

POST http://localhost:3000/register
Content-Type: application/json

{
"name": "full-name",
"email": "email-address",
"password": "password",
"password_confirmation": "password"
}

Email Verification

Verify a user's email address

POST http://localhost:3000/email/verify?email={email-address}&signature={signature}

The email address and signiture are provided in the query string and can be found in the VerifyEmail mailer that get's sent to the user. When the user clicks on the link in the email, the user will be redirected to "CLIENT_URL/email/verify?email=email-address&signature=signature".

Here, you can extract the email address and signature from the query string and verify the email address by sending a post request to "/email/verify" with the extracted email address and signature.

Resend Mail

Resend an email verification email to a user

POST http://localhost:3000/email/resend
Content-Type: application/json

{
"email": "email-address"
}

Forgot Password

Request a password reset email

POST http://localhost:3000/password/forgot
Content-Type: application/json

{
"email": "email-address"
}

Reset Password

Reset a password

POST http://localhost:3000/password/reset
Content-Type: application/json

{
"password": "password",
"password_confirmation": "password",
}

The email address and signiture are provided in the query string and can be found in the ForgotPassword mailer that get's sent to the user. When the user clicks the link in the email, the user will be redirected to {CLIENT_URL}/password/reset?email={email-address}&signature={signature}.

Here, you can extract the email address and signature from the query string and reset the user's password by sending a post request to /password/reset with the extracted email address and signature.

Authentication Events

Formidable provides a number of events that can be used to hook into your application's authentication.

beforeLogin

The beforeLogin event is fired before a user is logged in:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeLogin do(request, reply)
# Do something

beforeLogout

The beforeLogout event is fired before a user is logged out:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeLogout do(request, reply)
# Do something

beforeRegister

The beforeRegister event is fired before a user is registered:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeRegister do(request, reply)
# Do something

beforeVerify

The beforeVerify event is fired before a user email is verified:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeVerify do(request, reply)
# Do something

beforeResend

The beforeResend event is fired before a user verification email is resent:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeResend do(request, reply)
# Do something

beforeForgot

The beforeForgot event is fired before a user password reset email is sent:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeForgot do(request, reply)
# Do something

beforeReset

The beforeReset event is fired before a user password is reset:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.beforeReset do(request, reply)
# Do something

onAuthenticated

The onAuthenticated event is fired after a user is logged in:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onAuthenticated do(request, reply)
# Do something

onRegistered

The onRegistered event is fired after a user is registered:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onRegistered do(request, reply)
# Do something

Custom Authentication Handlers

Formidable provides an easy way to write your own authentication handlers.

onLogin

The onLogin hook is used to handle the login process:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onLogin do(request, reply)
# Log the user in

onRegister

The onRegister hook is used to handle the registration process:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onRegister do(request, reply)
# Register the user

onForgot

The onForgot hook is used to handle the forgot password process:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onForgot do(request, reply)
# Send the user a password reset email

onReset

The onReset hook is used to handle the password reset process:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onReset do(request, reply)
# Reset the user's password

onVerification

The onVerification hook is used to handle the email verification process:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onVerification do(request, reply)
# Verify the user's email address

onEmailResend

The onEmailResend hook is used to handle the email verification resend process:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'

export class AppServiceResolver < ServiceResolver

def boot
Auth.onEmailResend do(request, reply)
# Resend the user's email verification email

Authentication Mailers

By default, Formidable provides VerifyEmail and ResetPassword mailers that can be used to send email verification and password reset emails to your users:

app/Resolvers/AppServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'
import { VerifyEmail } from '../Mail/VerifyEmail'
import { ResetPassword } from '../Mail/ResetPassword'

export class AppServiceResolver < ServiceResolver

def boot
Auth
.verificationMailer(VerifyEmail)
.resetPasswordMailer(ResetPassword)

Protecting Routes

Formidable provides an auth middleware that can be used to require users to be logged in before accessing a route:

Route.get('ping', do 'pong').middleware(['auth'])

JWT

If you want to use JWT tokens for authentication, you can use the jwt middleware:

app/Resolvers/RouterServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'
import { Route } from '@formidablejs/framework'

export class RouterServiceResolver < ServiceResolver

def boot
Route.group { middleware: 'jwt' }, do
Auth.routes!

require '../../routes/api'

When logging your users in, a JWT token will be returned in the response:

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjQ5YTNkZWY0MDkxMzFjNThjNGY3NzYwNWU2NjNmYmRmIiwiaWF0IjoxNjM4ODA0NzgyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAifQ.A008sYS3973q-6uH2cQbgPf4Xq-v93UCvNLql0knIJ8",
"type": "Bearer",
"user": {
"name": "Donald",
"email": "donaldpakkies@gmail.com",
"email_verified_at": null,
"created_at": "2021-12-06T15:41:48.000Z",
"updated_at": "2021-12-06T15:41:48.000Z"
}
}

Now, to access /ping you can pass the JWT token in the Authorization header as a Bearer token:

POST http://localhost:3000/ping
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjQ5YTNkZWY0MDkxMzFjNThjNGY3NzYwNWU2NjNmYmRmIiwiaWF0IjoxNjM4ODA0NzgyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAifQ.A008sYS3973q-6uH2cQbgPf4Xq-v93UCvNLql0knIJ8

Session

If you want to use sessions for authentication, you can use the session middleware:

app/Resolvers/RouterServiceResolver.imba
import { AuthService as Auth } from '@formidablejs/framework'
import { ServiceResolver } from '@formidablejs/framework'
import { Route } from '@formidablejs/framework'

export class RouterServiceResolver < ServiceResolver

def boot
Route.group { middleware: 'session' }, do
Auth.routes!

require '../../routes/api'

When logging your users in, a new session will be created and a cookie will be set in the response. You may need to set a X-CSRF-TOKEN header in your authentication routes if you have CSRF protection enabled:

POST http://localhost:3000/login
X-CSRF-TOKEN: qpCuH2vmjhxgcDMkVnzfdV4tsdr9InVBgZzPTOw6Rt3YG8Hz-t1WbthldpuBOV3hrtUGMihiTraU
Content-Type: application/json

{
"email": "email-address"
"password": "password"
}

See CSRF Protection for more information.