> 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).