API tokens
The API guard uses the database-backed opaque access token to authenticate the user requests. You may want to use the API guard when creating an API that should be accessed by a third-party client, or for any other system that does not support cookies.
Tokens storage
The API tokens guard allows you store tokens either in a SQL database or store them inside Redis. Both the storage options have their own use cases.
SQL storage
The SQL storage method is suitable when API tokens are not the primary mode of authentication. For example: You may want to allow the users of your application to create personal access tokens (just like the way GitHub does) and authenticate the API requests using that.
In this scenario, you will not generate too many tokens in bulk and also most of the tokens will live forever.
Configuration for tokens is managed inside the config/auth.ts file under the guard config object.
{
  api: {
    driver: 'oat',
    provider: {
      driver: 'lucid',
      identifierKey: 'id',
      uids: ['email'],
      model: () => import('App/Models/User'),
    },
    tokenProvider: {
      type: 'api',
      driver: 'database',
      table: 'api_tokens',
      foreignKey: 'user_id',
    },
  }
}
type
The type property holds the type of the token you are generating. Make sure to give it a unique name when you have multiple API token guards in use.
The unique name ensures that two guards generating the token for the same user does not have overlap or any conflicts.
driver
The name of the driver. It will always be database when storing the tokens inside a SQL table.
table
The database table to use for storing the tokens. During the initial setup process, AdonisJS will create the migration file for the tokens table. However, you can also create a migration manually and copy the contents from the stub file
foreignKey
The foreign key to build the relationship between the user and the token. Later, this will allow you to also list all the tokens for a given user.
Redis storage
The redis storage is suitable when API tokens are the primary mode of authentication. For example: You authenticate the requests from your mobile app using token-based authentication.
In this scenario, you would also want tokens to expire after a given period of time and redis can automatically clear the expired tokens from its storage.
Configuration for tokens is managed inside the config/auth.ts file under the guard config object.
{
  api: {
    driver: 'oat',
    provider: {
      driver: 'lucid',
      identifierKey: 'id',
      uids: ['email'],
      model: () => import('App/Models/User'),
    },
    tokenProvider: {
      type: 'api',
      driver: 'redis',
      redisConnection: 'local',
      foreignKey: 'user_id',
    },
  }
}
type
The type property holds the type of the token you are generating. Make sure to give it a unique name when you have multiple API token guards in use.
The unique name ensures that two guards generating the token for the same user does not have overlap or any conflicts.
driver
The name of the driver. It will always be redis when storing the tokens in a redis database.
redisConnection
Reference to a connection defined inside the config/redis.ts file. Make sure to read the redis guide
 for the initial setup.
foreignKey
The foreign key to build the relationship between the user and the token.
Generating tokens
You can generate an API token for a user using the auth.generate or the auth.attempt method. The auth.attempt method lookup the user from the database and verifies their password.
- If the user credentials are correct, it will internally call the 
auth.generatemethod and returns the token. - Otherwise an InvalidCredentialsException is raised.
 
import Route from '@ioc:Adonis/Core/Route'
Route.post('login', async ({ auth, request, response }) => {
  const email = request.input('email')
  const password = request.input('password')
  try {
    const token = await auth.use('api').attempt(email, password)
    return token
  } catch {
    return response.unauthorized('Invalid credentials')
  }
})
You can either manually handle the exception and return a response, or let the exception handle itself and create a response using content negotiation .
auth.generate
If the auth.attempt lookup strategy does not fit your use case, then you can manually lookup the user, verify their password and call the auth.generate method to generate a token for them.
The auth.login method is an alias for the auth.generate method.
import User from 'App/Models/User'
import Route from '@ioc:Adonis/Core/Route'
import Hash from '@ioc:Adonis/Core/Hash'
Route.post('login', async ({ auth, request, response }) => {
  const email = request.input('email')
  const password = request.input('password')
  // Lookup user manually
  const user = await User
    .query()
    .where('email', email)
    .where('tenant_id', getTenantIdFromSomewhere)
    .whereNull('is_deleted')
    .firstOrFail()
  // Verify password
  if (!(await Hash.verify(user.password, password))) {
    return response.unauthorized('Invalid credentials')
  }
  // Generate token
  const token = await auth.use('api').generate(user)
})
Managing tokens expiry
You can also define the expiry for the token at the time of the generating it.
await auth.use('api').attempt(email, password, {
  expiresIn: '7 days'
})
await auth.use('api').generate(user, {
  expiresIn: '30 mins'
})
The redis driver will automatically delete the expired tokens. However, for SQL storage, you will have write a custom script and delete token with expires_at timestamp smaller than today.
Token properties
Following is the list of properties on the token object generated using the auth.generate method.
type
The token is always set to 'bearer'.
user
The user for which the token was generated. The value of the user relies on the underlying user provider used by the guard.
expiresAt
An instance of the luxon Datetime representing a static time at which the token will expire. Only exists, if have explicitly defined the expiry for the token.
expiresIn
Time in seconds after which the token will expire. It is a static value and does not change as the time passes by.
meta
Any meta data attached with the token. You can define the meta data in the options object at the time of generating the token.
The underlying storage drivers will persist the meta data to the database. In case of SQL, make sure to also create the required columns.
await auth.use('api').attempt(email, password, {
  ip_address: '192.168.1.0'
})
name
The name to associate with the token. This is usually helpful when you allow the users of your application to generate personal access tokens (just like the way GitHub does) and give them a memorable name.
The name property only exists, when you have defined it at the time of generating the token.
await auth.use('api').attempt(email, password, {
  name: 'For the CLI app'
})
token
The value for the generated token. You must share this value with the client and the client must store it securely.
You cannot get access to this value later, as the value stored inside the database is a hash of the token that cannot be converted to a plain value.
tokenHash
The value stored inside the database. Make sure to never share the token hash with the client.
During the auth.authenticate request, we will compare the value provided by the client against the token hash.
toJSON
Converts the token to an object that you can send back in response to a request. The toJSON method contains the following properties.
{
  type: 'bearer',
  token: 'the-token-value',
  expires_at: '2021-04-28T17:43:37.235+05:30'
  expires_in: 604800
}
Authenticate subsequent requests
Once the client receives the API token, they must send it back on every HTTP request under the Authorization header. The header must be formatted as follows:
Authorization = Bearer TOKEN_VALUE
You can verify if the token is valid or not using the auth.authenticate method. The AuthenticationException
 is raised, if the token is invalid or the user does not exists inside the database.
Otherwise, you can access the logged-in user using the auth.user property.
import Route from '@ioc:Adonis/Core/Route'
Route.get('dashboard', async ({ auth }) => {
  await auth.use('api').authenticate()
  console.log(auth.use('api').user!)
})
Calling this method manually inside every single route is not practical and hence you can make use of the auth middleware stored inside the ./app/Middleware/Auth.ts file.
Revoke tokens
During the logout phase, you can revoke the token by deleting it from the database. The token again must be sent under the Authorization header.
The auth.revoke method will remove the token sent during the current request from the database.
import Route from '@ioc:Adonis/Core/Route'
Route.post('/logout', async ({ auth, response }) => {
  await auth.use('api').revoke()
  return {
    revoked: true
  }
})
Other methods/properties
Following is the list of available methods/properties available for the api guard.
isLoggedIn
Find if user is logged in or not. The value is true right after calling the auth.generate method or when the auth.authenticate check passes.
await auth.use('api').authenticate()
auth.use('api').isLoggedIn // true
await auth.use('api').attempt(email, password)
auth.use('api').isLoggedIn // true
isGuest
Find if the user is a guest (meaning not logged in). The value is always the opposite of the isLoggedIn flag.
isAuthenticated
Find if the current request has passed the authentication check. This flag is different from the isLoggedIn flag and NOT set to true during the auth.login call.
await auth.use('api').authenticate()
auth.use('api').isAuthenticated // true
await auth.use('api').attempt(email, password)
auth.use('api').isAuthenticated // false
isLoggedOut
Find if the token was revoked during the current request. The value will be true right after calling the auth.revoke method.
await auth.use('api').revoke()
auth.use('api').isLoggedOut
authenticationAttempted
Find if an attempt to authenticate the current request has been made. The value is set to true when you call the auth.authenticate method
auth.use('api').authenticationAttempted // false
await auth.use('api').authenticate()
auth.use('api').authenticationAttempted // true
provider
Reference to the underlying user provider used by the guard.
tokenProvider
Reference to the underlying token provider used by the guard.
verifyCredentials
A method to verify the user credentials. The auth.attempt method uses this method under the hood. The InvalidCredentialsException
 exception is raised when the credentials are invalid.
try {
  await auth.use('api').verifyCredentials(email, password)
} catch (error) {
  console.log(error)
}
check
The method is same as the auth.authenticate method. However, it does not raise any exception when the request is not authenticated. Think of it as an optional attempt to check if the token is valid for the current request or not.
await auth.use('api').check()
if (auth.use('api').isLoggedIn) {
}