Introduction

AdonisJS comes with a fully fledged authentication system to authenticate the users of your application using sessions, basic auth or API tokens.

The support for authentication is added by the @adonisjs/auth package and it must be installed separately.

The auth package relies on the @adonisjs/lucid package. Make sure to configure lucid first.

npm i @adonisjs/auth
node ace configure @adonisjs/auth
# CREATE: app/Models/User.ts
# CREATE: database/migrations/1619578304190_users.ts
# CREATE: contracts/auth.ts
# CREATE: config/auth.ts
# CREATE: app/Middleware/Auth.ts file already exists
# CREATE: app/Middleware/SilentAuth.ts file already exists
# UPDATE: .adonisrc.json { providers += "@adonisjs/auth" }
# CREATE: ace-manifest.json file
  • Multiple guards for authentication. Sessions, API tokens, and Basic auth
  • Extensible API to add custom guards and user providers

Config

The configuration for the auth package is stored inside the config/auth.ts file. Inside this file you can define one or more guards to authenticate users. A guard is a combination of a user provider and one of the available authentication driver.

import { AuthConfig } from '@ioc:Adonis/Addons/Auth'
const authConfig: AuthConfig = {
guard: 'web',
guards: {
web: {
driver: 'session',
provider: {
driver: 'lucid',
identifierKey: 'id',
uids: ['email'],
model: () => import('App/Models/User'),
},
},
},
}
export default authConfig

guard

The top level guard property defines the default guard to use for authentication. It must be defined inside the guards list.


guards

The guards object is a key-value pair of the guards you want to use in your application. You can create multiple guards using the same or a different driver.


guards.driver

The driver to use for login and authenticating users. You can use one of the pre-existing drivers or extend the Auth module to add your own.


guards.provider

The provider property configures a user provider to lookup users. You can use one of the pre-existing providers or extend the Auth module to add your own.

Following is the list of available drivers for user lookup. Rest of the config values are dependent upon the selected driver.


Configuring new guards/providers

You can also configure new guards and the providers after initial setup. The first step is to register them inside the contracts/auth.ts file to inform the TypeScript static compiler.

You can add a new provider inside the ProvidersList interface. The key is the name of provider, alongside the types for both the config and the implementation.

The GuardsList interface is the list of all the guards you want to use. The key is the name of the guard, alongside the types for both the guard config and its implementation.

contracts/auth.ts
declare module '@ioc:Adonis/Addons/Auth' {
interface ProvidersList {
user: {
implementation: LucidProviderContract<typeof User>,
config: LucidProviderConfig<typeof User>,
},
apps: {
implementation: LucidProviderContract<typeof App>,
config: LucidProviderConfig<typeof App>,
}
}
interface GuardsList {
web: {
implementation: SessionGuardContract<'user', 'web'>,
config: SessionGuardConfig<'user'>,
},
api: {
implementation: OATGuardContract<'apps', 'api'>,
config: OATGuardConfig<'apps'>,
}
}
}

Once, you have added the new guard(s) or provider(s) inside the contracts file, the TypeScript compiler will automatically validate the config file, forcing you to define the configuration for it as well.

Migrations

The setup process also creates the migration files for the users table and optionally for the tokens table (if using the API tokens guard with SQL storage).

The filename of the migrations uses the current timestamp and is placed after all the existing migrations.

There are chances that some of your tables needs to create a foreign key constraint with the users table, hence the users table migration must run before those migrations.

In this scenario, you can manually rename the users table migration file and use a smaller timestamp to move it ahead of the other migration files.

Usage

You can access the auth instance inside your route handlers using the ctx.auth property. The auth object allows you to both login users and authenticate subsequent requests.

Login user
Route.post('login', async ({ auth, request }) => {
const email = request.input('email')
const password = request.input('password')
await auth.use('web').attempt(email, password)
})
Authenticate subsequent request
Route.get('dashboard', async ({ auth }) => {
await auth.use('web').authenticate()
// ✅ Request authenticated
console.log(auth.user!)
})

Beyond the basic usage, we recommend you to read the guides for the individual guards, as their API and flow may vary.

Reference inside templates

The ctx.auth property is also shared with the templates. You can use it to display the specific portion of your markup conditionally.

@if(auth.isLoggedIn)
<p> Hello {{ auth.user.username }} </p>
@endif

Providers config reference

Following is the reference of user providers config and contracts.

Lucid provider

The lucid provider uses the data models to lookup users from the databases. The provider must be configured inside the contracts file first.

import User from 'App/Models/User'
interface ProvidersList {
providerName: {
implementation: LucidProviderContract<typeof User>,
config: LucidProviderConfig<typeof User>,
}
}

Following is the list of all the available configuration options.

{
provider: {
driver: 'lucid',
identifierKey: 'id',
uids: ['email'],
model: () => import('App/Models/user'),
connection: 'pg',
hashDriver: 'argon',
}
}

driver

The driver name must always be set to lucid.


identifierKey

The identifierKey is usually the primary key on the configured model. The authentication package needs it to uniquely identify a user.


uids

An array of model columns to use for the user lookup. The auth.login method uses the uids to find a user by the provided value.

For example: If your application allows login with email and username both, then you must define them as uids. Also, you need to define the model column names and not the database column names.


model

The model to use for user lookup. It must be lazily imported using a closure.

{
model: () => import('App/Models/user'),
}

connection

The database connection to use to make the SQL queries. If not defined, the model connection will be used.


hashDriver

The driver to use for verifying the user password hash. It is used by the auth.login method. If not defined, we will use the default hash driver from the config/hash.ts file.


Database provider

The database provider queries the database directly using the Database query builder . You must register the provider inside the contracts file first.

interface ProvidersList {
providerName: {
implementation: DatabaseProviderContract<DatabaseProviderRow>,
config: DatabaseProviderConfig,
}
}

Following is the list of available configuration options.

{
provider: {
driver: 'database'
identifierKey: 'id',
uids: ['email'],
usersTable: 'users',
connection: 'pg'
hashDriver: 'argon'
}
}

driver

The driver name must always be set to database.


identifierKey

The identifierKey is usually the primary key of the configured database table. The authentication package needs it to uniquely identify a user.


uids

An array of model columns to use for the user lookup. The auth.login method uses the uids to find a user by the provided value.

For example: If your application allows login with email and username both, then you must define them as uids. Also, you need to define the model column names and not the database column names.


usersTable

The name of the database table to use for users lookup.

{
usersTable: 'users'
}

connection

The database connection to use to make the SQL queries. If not defined, the default connection from the config/database.ts file is used.


hashDriver

The driver to use for verifying the user password hash. It is used by the auth.login method. If not defined, we will use the default hash driver from the config/hash.ts file.