Authentication with multiple IDs in AdonisJS 5

More often than not we would expect users to log in to our application with an ID and a password combination. The ID can be an email address, username, or anything that's unique for that matter. But there are times users would rather prefer to log in to their accounts with any of the unique IDs and a password. This can be tricky to implement but with AdonisJS 5, we just need to change a config detail.

In this tutorial, I'll be showing how to allow users to log in with multiple IDs in an AdonisJS 5 application.

Getting started

To get started, let's paint some assumptions that we'll build on in the rest of the tutorial. First, I'll assume you already have an AdonisJS 5 application and have installed and set up the auth module. Also, that the users table has email, username, and password columns.

With all the assumptions out of the way, let's get down to business. Basically, we want users to be able to log in with either their email address or username plus their password.

To that, we need to first update the ids array inside config/auth.ts as below:

// config/auth.ts

uids: ['email', 'username']

When a user tries to log in, AdonisJS will search the user-submitted details against the columns specified in the ids array to find the user record. So we simply add the columns (in this case, email and username) we want users to be able to log in with inside the array.

Now, we can use the attempt() as below;

public async login ({ request, auth }: HttpContextContract) {
  const { userId, password } = request.all()

  await auth.attempt(userId, password)

  // redirect or do other things
}

userId will be either the user's email address or username. And that's basically all we need to do.

Sound too good to be true? Continue reading...

How does that work

Let's dig a little deeper to understand how on heck does that just works. The attempt() takes in the uid and password as arguments and under the hood, it calls findByUid():

// https://github.com/adonisjs/auth/blob/develop/src/UserProviders/Lucid/index.ts#L135

public async findByUid(uidValue: string) {
  const { query } = await this.getModelQuery()

  this.config.uids.forEach((uid) => query.orWhere(uid, uidValue))

  return this.findUser(query)
}

As you can see, the method simply loops through the uids array, and for each of the uid (column), it checks the user-submitted value against it. Since it performs this check using orWhere(), whichever uid (column) that matches the user value will be used to retrieve the user record.

Conclusion

So in this tutorial, we looked at how to allow users to log in with multiple IDs in an AdonisJS 5 application. Then we went to further to look at how this works under the hood.