> adonis install @adonisjs/auth
You are viewing the legacy version of AdonisJS. Visit https://adonisjs.com for newer docs. This version will receive security patches until the end of 2021.
The AdonisJs auth provider is a fully featured system to authenticate HTTP requests using multiple authenticators.
Using authenticators you can build traditional session based login systems and secure your APIs.
| For opinionated user profile management, check out the official Adonis Persona package – a simple, functional service to let you create, verify and update user profiles in AdonisJs. |
Each authenticator is a combination of authentication scheme and serializer.
Session (session)
Basic Auth (basic)
JWT (jwt)
Personal API Tokens (api)
Lucid (lucid)
Database (database)
Authentication is divided into two broad categories: Stateful and Stateless.
Session-based authentication is considered Stateful since logged in users can navigate to different areas of the application without resending their credentials.
Stateless authentication requires the user to resend their credentials on each HTTP request, which is very common with APIs.
AdonisJs provides necessary tooling and helpers to manage both types of authentication with ease.
The AdonisJs auth provider uses the Hash module to verify passwords.
Always hash your passwords before saving them to the database.
The AdonisJs auth provider comes pre-installed with fullstack and api boilerplates.
If the auth provider is not already set up, follow the instructions below.
First, run the adonis command to download the auth provider:
> adonis install @adonisjs/auth
Next, register the auth provider inside the start/app.js file:
const providers = [
'@adonisjs/auth/providers/AuthProvider'
]
Finally, register the auth middleware inside the start/kernel.js file:
const globalMiddleware = [
'Adonis/Middleware/AuthInit'
]
const namedMiddleware = {
auth: 'Adonis/Middleware/Auth',
guest: 'Adonis/Middleware/AllowGuestOnly'
}
Your authentication configuration is saved inside the config/auth.js file.
By default, the session authenticator is used to authenticate app requests.
Let’s start with the example of logging in a user, then only showing them their profile if they are logged in.
First, add the following routes to the start/routes.js file:
Route
.post('login', 'UserController.login')
.middleware('guest')
Route
.get('users/:id', 'UserController.show')
.middleware('auth')
Next, create the UserController via the adonis command:
> adonis make:controller User
Add the login method to the UserController:
class UserController {
async login ({ auth, request }) {
const { email, password } = request.all()
await auth.attempt(email, password)
return 'Logged in successfully'
}
}
The login method above extracts the user’s email and password from the request and logs them in if their credentials are valid.
Finally, add the show method to the UserController:
class UserController {
async login () {
...
}
show ({ auth, params }) {
if (auth.user.id !== Number(params.id)) {
return "You cannot see someone else's profile"
}
return auth.user
}
}
The show method above checks if the id route parameter equals the currently logged in user id. If so, the authenticated user model is returned (which AdonisJS converts to JSON in the final response).
module.exports = {
authenticator: 'session',
session: {
serializer: 'Lucid',
scheme: 'session',
model: 'App/Models/User',
uid: 'email',
password: 'password'
}
}
| Key | Values | Description |
|---|---|---|
serializer |
|
Serializer used to fetch the user from the database. |
scheme |
|
Scheme used to fetch and authenticate user credentials. |
uid |
Database field name |
Database field used as the unique identifier for a given user. |
password |
Database field name |
Field used to verify the user password. |
model |
Model namespace ( |
Model used to query the database, applicable only when using the |
table |
Database table name ( |
Applicable only when using the |
The session authenticator exposes the following methods to log in and authenticate users.
Login via uid and password, throwing an exception if no user is found or the password is invalid:
await auth.attempt(uid, password)
Login via user model instance, not verify anything but simply marking the user as logged in:
const user = await User.find(1)
await auth.login(user)
Login a via user id, querying the database to ensure the user exists:
await auth.loginViaId(1)
When calling methods like attempt, login or loginViaId, chain the remember method to ensure users stay logged in after closing their browser:
await auth
.remember(true)
.attempt(email, password)
The remember method creates a token for the user inside the tokens table. If you ever want to revoke the long-lived session of a particular user, simply set is_revoked to true.
|
Check if a user is already logged in by reading their session:
try {
await auth.check()
} catch (error) {
response.send('You are not logged in')
}
Returns the logged in user instance (via the check method):
try {
return await auth.getUser()
} catch (error) {
response.send('You are not logged in')
}
As basic authentication is stateless with users passing credentials per request, there is no concept of login and logout.
The Authorization = Basic <credentials> header must be set to authenticate basic auth requests, where <credentials> is a base64 encoded string of uid:password, where uid is the uid database field defined in the config/auth.js file.
|
The basic authenticator exposes the following methods to authenticate users.
Check the user’s basic auth credentials in the request header, verifying the user’s existence and validating their password:
try {
await auth.check()
} catch (error) {
response.send(error.message)
}
Returns the logged in user instance (via the check method):
try {
return await auth.getUser()
} catch (error) {
response.send('Credentials missing')
}
JWT authentication is an industry standard to implement stateless authentication via string tokens.
AdonisJs supports JWT tokens out of the box via its jwt authenticator.
The Authorization = Bearer <token> header must be set to authenticate jwt auth requests, where <token> is a valid JWT token.
|
module.exports = {
authenticator: 'jwt',
jwt: {
serializer: 'Lucid',
model: 'App/Models/User',
scheme: 'jwt',
uid: 'email',
password: 'password',
options: {
secret: Config.get('app.appKey'),
// For additional options, see the table below...
}
}
}
| Key | Values | Default Value | Description |
|---|---|---|---|
algorithm |
|
|
Algorithm used to generate tokens. |
expiresIn |
Valid time in seconds or ms string |
null |
When to expire tokens. |
notBefore |
Valid time in seconds or ms string |
null |
Minimum time to keep tokens valid. |
audience |
String |
null |
|
issuer |
Array or String |
null |
|
subject |
String |
null |
|
public |
String |
null |
|
To secure JWT using `RS256` asymmetric algorithm, you need to explictly provide `algorithm` option and set it to `RS256`.
You must provide your `private key` via `secret` option which will be used by the framework to sign your JWT.
And you must provide your `public key` via `public` option, which will be used by the framework
to verify the JWT.
const fs = use("fs");
module.exports = {
authenticator: 'jwt',
jwt: {
//...
options: {
algorithm: 'RS256',
secret: fs.readFileSync('absolute-path-to-your-private-key-file'),
public: fs.readFileSync('absolute-path-to-your-public-key-file'),
// For additional options, see the table above...
}
}
}
The jwt authenticator exposes the following methods to generate JWT tokens and authenticate users.
Validate the user credentials and generate a JWT token in exchange:
await auth.attempt(uid, password)
{
type: 'type',
token: '.....',
refreshToken: '....'
}
Generate JWT token for a given user:
const user = await User.find(1)
await auth.generate(user)
You can optionally pass a custom object to be encoded within the token. Passing jwtPayload=true encodes the user object within the token.
Instruct the JWT authenticator to generate a refresh token as well:
await auth
.withRefreshToken()
.attempt(uid, password)
The refresh token is generated so that the clients can refresh the actual jwt token without asking for user credentials again.
Generate a new JWT token using the refresh token. Passing jwtPayload=true encodes the user object within the token.
const refreshToken = request.input('refresh_token')
await auth.generateForRefreshToken(refreshToken, true)
When generating a new jwt token, the auth provider does not reissue a new refresh token and instead uses the old one. If you want, you can also regenerate a new refresh token:
await auth
.newRefreshToken()
.generateForRefreshToken(refreshToken)
Checks if a valid JWT token has been sent via the Authorization header:
try {
await auth.check()
} catch (error) {
response.send('Missing or invalid jwt token')
}
Returns the logged in user instance (via the check method):
try {
return await auth.getUser()
} catch (error) {
response.send('Missing or invalid jwt token')
}
Personal API tokens were made popular by Github for use in scripts as a revocable substitute for traditional email and password authentication.
AdonisJs allows you to build apps where your users can create personal API tokens and use them to authenticate.
The Authorization = Bearer <token> header must be set to authenticate api auth requests, where <token> is a valid API token.
|
The api authenticator exposes the following methods to generate API tokens and authenticate users.
Valid the user credentials and then generate a new token for them:
const token = await auth.attempt(uid, password)
{
type: 'bearer',
token: '...'
}
Generate token for a given user:
const user = await User.find(1)
const token = await auth.generate(user)
Checks if a valid API token has been passed via the Authorization header:
try {
await auth.check()
} catch (error) {
response.send('Missing or invalid api token')
}
Returns the logged in user instance (via the check method):
try {
await auth.getUser()
} catch (error) {
response.send('Missing or invalid api token')
}
The auth provider makes it simple to switch between multiple authenticators at runtime by calling the authenticator method.
Assuming the user is logged in using the session authenticator, we can generate a JWT token for them as follows:
// loggedin user via sessions
const user = auth.user
auth
.authenticator('jwt')
.generate(user)
The auth middleware automates authentication for any applied routes.
It is registered as a named middleware inside the start/kernel.js file:
const namedMiddleware = {
auth: 'Adonis/Middleware/Auth'
}
Usage:
Route
.get('users/profile', 'UserController.profile')
.middleware(['auth'])
The guest middleware verifies the user is not authenticated.
It is registered as a named middleware inside the start/kernel.js file:
const namedMiddleware = {
guest: 'Adonis/Middleware/AllowGuestOnly'
}
Usage:
// We don't want our logged-in user to access this view
Route
.get('login', 'AuthController.login')
.middleware(['guest'])
The auth provider adds a couple of helpers to the view instance so that you can write HTML around the state of a logged-in user.
The loggedIn tag can be used to write if/else around the loggedin user:
@loggedIn
<h2> Hello {{ auth.user.username }} </h2>
@else
<p> Please login </p>
@endloggedIn
The jwt and api schemes expose methods to revoke tokens using the auth interface.
For jwt, refresh tokens are only revoked, since actual tokens are never saved in the database.
|
The following method will revoke tokens by setting a flag in the tokens table:
const refreshToken = '' // get it from user
await auth
.authenticator('jwt')
.revokeTokens([refreshToken])
If true is passed as the 2nd argument, instead of setting the is_revoked database flag, the relevant row will be deleted from the database:
const refreshToken = '' // get it from user
await auth
.authenticator('jwt')
.revokeTokens([refreshToken], true)
To revoke all tokens, call revokeTokens without any arguments:
await auth
.authenticator('jwt')
.revokeTokens()
When revoking the api token for the currently loggedin user, you can access the value from the request header:
// for currently loggedin user
const apiToken = auth.getAuthHeader()
await auth
.authenticator('api')
.revokeTokens([apiToken])
This method works the same as the revokeTokens method, but instead you can specify the user yourself:
const user = await User.find(1)
await auth
.authenticator('jwt')
.revokeTokensForUser(user)
Tokens are saved in plain format inside the database, but are sent in encrypted form to the end-user.
This is done to ensure if someone accesses your database, they are not able to use your tokens directly (they’d have to figure out how to encrypt them using the secret key).