Session guard
The session guard uses the @adonisjs/session package to login and authenticate users during an HTTP request.
Sessions and cookies have been on the internet for a long time and work great for most applications. Therefore, we recommend using the session guard for server-rendered applications or an SPA web client on the same top-level domain.
Configuring the guard
The authentication guards are defined inside the config/auth.ts
file. You can configure multiple guards inside this file under the guards
object.
import { defineConfig } from '@adonisjs/auth'
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session'
const authConfig = defineConfig({
default: 'web',
guards: {
web: sessionGuard({
useRememberTokens: false,
provider: sessionUserProvider({
model: () => import('#models/user'),
}),
})
},
})
export default authConfig
The sessionGuard
method creates an instance of the SessionGuard class. It accepts a user provider that can be used to find users during authentication and an optional config object to configure the remember tokens behavior.
The sessionUserProvider
method creates an instance of the SessionLucidUserProvider class. It accepts a reference to the model to use for authentication.
Performing login
You can login a user using the guard.login
method. The method accepts an instance of the User model and creates a login session for them.
In the following example:
-
We use the
verifyCredentials
from the AuthFinder mixin to find a user by email and password. -
The
auth.use('web')
returns an instance of the SessionGuard configured inside theconfig/auth.ts
file. -
Next, we call the
guard.login(user)
method to create a login session for the user. -
Finally, we redirect the user to the
/dashboard
endpoint. Feel free to customize the redirect endpoint.
import User from '#models/user'
import { HttpContext } from '@adonisjs/core/http'
export default class SessionController {
async store({ request, auth, response }: HttpContext) {
/**
* Step 1: Get credentials from the request body
*/
const { email, password } = request.only(['email', 'password'])
/**
* Step 2: Verify credentials
*/
const user = await User.verifyCredentials(email, password)
/**
* Step 3: Login user
*/
await auth.use('web').login(user)
/**
* Step 4: Send them to a protected route
*/
response.redirect('/dashboard')
}
}
Protecting routes
You can protect routes from unauthenticated users using the auth
middleware. The middleware is registered inside the start/kernel.ts
file under the named middleware collection.
export const middleware = router.named({
auth: () => import('#middleware/auth_middleware')
})
Apply the auth
middleware to the routes you want to protect from unauthenticated users.
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', () => {})
.use(middleware.auth())
By default, the auth middleware will authenticate the user against the default
guard (as defined in the config file). However, you can specify an array of guards when assigning the auth
middleware.
In the following example, the auth middleware will attempt to authenticate the request using the web
and the api
guards.
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', () => {})
.use(
middleware.auth({
guards: ['web', 'api']
})
)
Handling authentication exception
The auth middleware throws the E_UNAUTHORIZED_ACCESS if the user is not authenticated. The exception is handled automatically using the following content-negotiation rules.
-
Request with
Accept=application/json
header will receive an array of errors with themessage
property. -
Request with
Accept=application/vnd.api+json
header will receive an array of errors as per the JSON API spec. -
The user will be redirected to the
/login
page for server-rendered applications. You can configure the redirect endpoint within theauth
middleware class.
Getting access to the logged-in user
You may access the logged-in user instance using the auth.user
property. The value is only available when using the auth
middleware or if you call the auth.authenticate
or auth.check
methods manually.
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', ({ auth }) => {
await auth.user!.getAllMetrics()
})
.use(middleware.auth())
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', ({ auth }) => {
/**
* First, authenticate the user
*/
await auth.authenticate()
/**
* Then access the user object
*/
await auth.user!.getAllMetrics()
})
Check if the request is authenticated
You can check if a request has been authenticated using the auth.isAuthenticated
flag. The value of auth.user
will always be defined for an authenticated request.
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', ({ auth }) => {
if (auth.isAuthenticated) {
await auth.user!.getAllMetrics()
}
})
.use(middleware.auth())
Get authenticated user or fail
If you do not like using the non-null assertion operator on the auth.user
property, you may use the auth.getUserOrFail
method. This method will return the user object or throw E_UNAUTHORIZED_ACCESS exception.
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.get('dashboard', ({ auth }) => {
const user = auth.getUserOrFail()
await user.getAllMetrics()
})
.use(middleware.auth())
Access user within Edge templates
The InitializeAuthMiddleware also shares the ctx.auth
property with Edge templates. Therefore, you can access the currently logged-in user via the auth.user
property.
@if(auth.isAuthenticated)
<p> Hello {{ auth.user.email }} </p>
@end
If you want to fetch logged-in user information on a non-protected route, you can use the auth.check
method to check if the user is logged-in and then access the auth.user
property. A great use case for this is displaying the logged-in user information on the website header of a public page.
{{--
This is a public page; therefore, it is not protected by the auth
middleware. However, we still want to display the logged-in
user info in the header of the website.
For that, we use the `auth.check` method to silently check if the
user is logged in and then displays their email in the header.
You get the idea!
--}}
@eval(await auth.check())
<header>
@if(auth.isAuthenticated)
<p> Hello {{ auth.user.email }} </p>
@end
</header>
Performing logout
You can logout a user using the guard.logout
method. During logout, the user state will be deleted from the session store. The currently active remember me token will also be deleted (if using remember me tokens).
import { middleware } from '#start/kernel'
import router from '@adonisjs/core/services/router'
router
.post('logout', async ({ auth, response }) => {
await auth.use('web').logout()
return response.redirect('/login')
})
.use(middleware.auth())
Using the Remember Me feature
The Remember Me feature automatically login user after their session expires. This is done by generating a cryptographically secure token and saving it as a cookie inside the user's browser.
After the user session has expired, AdonisJS will use the remember me cookie, verify the token's validity, and automatically re-create the logged-in session for the user.
Creating the Remember Me Tokens table
The remember me tokens are saved inside the database, and therefore, you must create a new migration to create the remember_me_tokens
table.
node ace make:migration remember_me_tokens
import { BaseSchema } from '@adonisjs/lucid/schema'
export default class extends BaseSchema {
protected tableName = 'remember_me_tokens'
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments()
table
.integer('tokenable_id')
.notNullable()
.unsigned()
.references('id')
.inTable('users')
.onDelete('CASCADE')
table.string('hash').notNullable().unique()
table.timestamp('created_at').notNullable()
table.timestamp('updated_at').notNullable()
table.timestamp('expires_at').notNullable()
})
}
async down() {
this.schema.dropTable(this.tableName)
}
}
Configuring the tokens provider
To read-write tokens, you will have to assign the DbRememberMeTokensProvider to the User model.
import { BaseModel } from '@adonisjs/lucid/orm'
import { DbRememberMeTokensProvider } from '@adonisjs/auth/session'
export default class User extends BaseModel {
// ...rest of the model properties
static rememberMeTokens = DbRememberMeTokensProvider.forModel(User)
}
Enabling Remember Me tokens inside the config
Finally, let's enable the useRememberTokens
flag on the session guard config inside the config/auth.ts
file.
import { defineConfig } from '@adonisjs/auth'
import { sessionGuard, sessionUserProvider } from '@adonisjs/auth/session'
const authConfig = defineConfig({
default: 'web',
guards: {
web: sessionGuard({
useRememberTokens: true,
rememberMeTokensAge: '2 years',
provider: sessionUserProvider({
model: () => import('#models/user'),
}),
})
},
})
export default authConfig
Remembering users during login
Once the setup is completed, you can generate the remember me token and cookie using the guard.login
method as follows.
import User from '#models/user'
import { HttpContext } from '@adonisjs/core/http'
export default class SessionController {
async store({ request, auth, response }: HttpContext) {
const { email, password } = request.only(['email', 'password'])
const user = await User.verifyCredentials(email, password)
await auth.use('web').login(
user,
/**
* Generate token when "remember_me" input exists
*/
!!request.input('remember_me')
)
response.redirect('/dashboard')
}
}
Using the guest middleware
The auth package ships with a guest middleware you can use to redirect the logged-in users from accessing the /login
page. This should be done to avoid creating multiple sessions for a single user on a single device.
import router from '@adonisjs/core/services/router'
import { middleware } from '#start/kernel'
router
.get('/login', () => {})
.use(middleware.guest())
By default, the guest middleware will check the user logged-in status using the default
guard (as defined in the config file). However, you can specify an array of guards when assigning the guest
middleware.
router
.get('/login', () => {})
.use(middleware.guest({
guards: ['web', 'admin_web']
}))
Finally, you can configure the redirect route for the logged-in users inside the ./app/middleware/guest_middleware.ts
file.
Events
Please check the events reference guide to view the list of available events emitted by the Auth package.