Auth.js adoption guide: Overview, examples, and alternatives

Auth JS (also known as Next Auth) is a popular open-source library to provide login support to Javascript based applications. Being a vercel product it has first class support for Nextjs.

multi-coloured image background with Auth-js logo in the foreground.

When building web applications, we often have to implement authentication to protect the app against unauthorized access to user data and improve its integrity. Your specific auth needs depend on the type of app you’re building, but authentication in general is crucial for any app that collects or stores users’ data.

If you’re deliberating what level of authentication your app requires, it helps to know details like what actions will be performed and who will perform them. You may want your users to validate their identity using authentication methods like their username, email, and password.

Building authentication into applications comes with challenges such as password vulnerabilities, improper session management, handling and storing user credentials, and more. Auth.js was created as a comprehensive tool to make adding authentication to web apps easier and more secure.

In this guide, we’ll learn what Auth.js is, cover its history, and discuss why you should use it in your projects. To demonstrate the many excellent features of Auth.js, we’ll build a simple Next.js application that implements user authentication such as login, signup, and session management.

What is Auth.js?

Auth.js is the most comprehensive JavaScript library for authentication in any web application. It simplifies implementing user authentication mechanisms into web applications. With Auth.js, you have the flexibility to leverage various authentication strategies, from simple username-password combinations to complex services like OAuth or SSO systems.

The Auth.js library has inbuilt support for a lot of databases, including MongoDB, PostgreSQL, MDQL, MariaDB, and more. It will also work with no database at all when you integrate it with OAuth services or JSON Web Tokens.

History of Auth.js

Auth.js was formally called NextAuth when Iain Collins first developed it in 2016. At that time, it looked quite different from the tool we know today.

In 2020, the project was rewritten and relaunched by Balázs Orbán with a focus on simplifying authentication for Next.js applications. This is considered the true beginning of NextAuth.

When the library started getting adopted by more developers and implementing support for more frameworks and use cases, its name was changed from NextAuth to Auth.js. This move, which happened in late 2022, expanded the scope of the framework beyond Next.js apps to support other React frameworks.

Auth.js as we know it today is a comprehensive solution that simplifies all the complexities and security concerns associated with traditional authentication methods. Due to its active community of developers and contributors, Auth.js has continually advanced to keep up with newer security standards and best practices.

Further reading :

How Auth.js works?

Auth.js handles user authentication and authorization in a web application. It handles major functionalities such as user registration, login, password and session management, and control of accessibility to users. The diagram below shows how it works in a web application:

Diagram Showing Auth Js Workflow In Web App

Why choose Auth.js?

For an important feature like authentication and authorization that affects your app’s security, you should consider why you should use Auth.js over other authentication frameworks. Let’s discuss some of the pros and cons of using Auth.js as your go-to authentication framework:

  • Performance — By design, Auth.js is incredibly high-performing and only minimally impacts the time it takes to load an application. It uses a performant token-based authentication to reduce the server load, as opposed to the traditional session-based approaches. Its architecture ensures the authentication processes you use are optimized to be very fast
  • Bundle size — The core Auth.js library was built to be lightweight, which makes your application bundle size small. This, in turn, helps your app load faster with optimal performance, as well as keeping your application highly performant even when you integrate many auth providers
  • Documentation — While Auth.js provides detailed guides, API references, and examples for developers, there are criticisms about it not providing detailed migration guides to enable developers to move to new versions of the framework. However, it’s clear the maintainers are invested in improving support and education for its users
  • Integrations — It’s easy to integrate Auth.js into a Next.js application with support for various databases and ORMS. It supports all popular auth providers such as Google, Facebook, GitHub, etc., providing plenty of options for developers without a third-party library
  • Ease of use_/_DX — Auth.js makes setting up authentication easier with a user-friendly API and and simpler configurations. Removing the hassle of implementing authentication from scratch allows you to focus on your development work. Auth.js also provides the best way to manage user session functionalities, such as persisting log-in, session timeouts, and cookie management
  • Learning curve — The learning curve for Auth.js is low for developers that are new to authentication, helping them focus more on the app rather than fighting with authentication issues
  • Community and ecosystem — Auth.js has an enormous, highly active developer community working to improve the framework with regular contributions, bug fixes, and new features. There are many blogs and tutorials available to help developers of any experience level to find resources to learn and answers

Even though Auth.js was developed to provide an extensive authentication framework that simplifies how we handle user authentications in web applications, it’s not a perfect tool. Some developers have faced challenges while using it, which has led to criticisms like the below:

  • Learning curve — Picking up Auth.js can be difficult for developers who have using other alternative authentication frameworks for a long time. These sets of developers may find the approach and concepts in Auth.js a little bit challenging, especially if they want to handle complex authentication
  • Migration to new versions — While the Auth.js documentation is good overall, there’s no proper migration guide showing how developers can migrate from Auth.js v4 to v5. As a result, many developers were not prepared to transition from v4 to v5 due to inconsistent and occasionally incomplete information across versions
  • Customizations — Although Auth.js provides various customization options, Auth.js v5 is notoriously hard to customize. This can be particularly frustrating for developers who need custom authentication to meet a specific need. For example, it’s difficult to add more fields to the default sign-in page or style the authentication flow
  • Unresolved issues — Although the Auth.js team works hard to improve the tool and fix bugs, the large number of GitHub issues and user complaints shows that many challenges have not yet been resolved, and more issues are opened almost daily. Instability like this makes most developers angry and wastes quite a good amount of development time, and could raise a red flag for a user looking to use the library for their projects
  • Overcomplicated — If your project is very small and you have simple authentication needs, Auth.js will be overkill. It may be better to use a simpler or custom authentication option
  • Framework-specific needs — While one can use Auth.js with other frameworks, it’s designed primarily for Next.js applications. Thus, some of these features will not be so seamless to integrate for developers using other frameworks

Despite these challenges, Auth.js still stands out as a reliable, complete authentication solution. It’s way better than building a custom authentication or using other smaller authentication solutions, which often take more development time and lack the rich features that Auth.js provides.

The learning curve might be a little steeper than others, but in the long run, it will save lots of time and effort. Also, the developers seem committed to enhancing the framework while addressing different concerns by the developers.

Remember every project is different and each developer has different needs, so providing a one-size-fits-all solution will be difficult.

Getting started with Auth.js: Key features to know

In this section, we’ll talk about how to set up Auth.js in your project and see some of its standout features in action.

To get started with Auth.js, you need to install it along with the required dependencies in your project. You can use a SvelteKit, Express.js, or Next.js application to get started.

For the demonstration in this tutorial, we’ll use it with a Next.js application. You can visit the official documentation for instructions on how to install it in your chosen environment.

First, create a new Next.js project by running the command below:

$ npx create-next-app@latest

Next install Next-auth :

$ npm install next-auth

Need to save the following environment vars in .env.local :

GITHUB_ID=your-github-client-id GITHUB_SECRET=your-github-client-secret

Next create the auth provider using NextAuth({}) component :

import NextAuth from 'next-auth'; import Providers from 'next-auth/providers'; const NextAuth = () => ({ providers: [ Providers.GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, }), ], pages: { signIn: '/auth/signin', }, }); export default NextAuth;

By default, Auth.js has provided you with a sign-in page. You can, however, make use of any custom sign-in page so that you can easily customize it. We did that by adding a pages object to the NextAuth configuration.

Now, create a pages/auth/signin.js file for the custom sign-in page and add the code snippets below:

import { signIn } from 'next-auth/client'; const SignIn = () => { return ( <div> <h1>Sign In</h1> <button onClick={() => signIn('github')}>Sign in with GitHub</button> </div> ); }; export default SignIn;

To protect a page in your application from unauthorized users — for example, the profile page — use the useSession hook provided by NextAuth. Create a pages/profile.js file and add the code snippets below:

import { useSession } from 'next-auth/client'; import { useEffect } from 'react'; import { useRouter } from 'next/router'; const ProfilePage = () => { const [session, loading] = useSession(); const router = useRouter(); useEffect(() => { if (!loading && !session) { router.push('/auth/signin'); } }, [loading, session, router]); if (loading) { return <p>Loading...</p>; } if (!session) { return null; } return <div>This a protected page</div>; }; export default ProfilePage;

Configurations and customizations

Auth.js offers various customizable configuration options for your authentication needs. These include:

  • Providers — You can add any number of providers, such as Google, GitHub, Facebook, etc., into your NextAuth configuration, which then becomes available for a user to sign in with
  • Callbacks — It allows you to define how you want the authentication to do after it has successfully authenticated a user
  • Pages — You can define the custom page you want to use for your SignIn, SignOut, and displaying authentication-related error messages
  • Session management — Configure session behavior. JWT and session expiration can be modified according to your needs

Now, let’s look at an example of how you can customize your NextAuth configuration to use multiple auth providers, callbacks, and custom pages.

Update your pages/api/auth/[...nextauth].js file with this code:

import NextAuth from 'next-auth'; import Providers from 'next-auth/providers'; export default NextAuth({ providers: [ Providers.GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, }), Providers.Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, }), ], callbacks: { async signIn(user, account, profile) { return true; }, async redirect(url, baseUrl) { return baseUrl; }, async session(session, token) { session.user.id = token.id; return session; }, async jwt(token, user, account, profile, isNewUser) { if (user) { token.id = user.id; } return token; }, }, pages: { signIn: '/auth/signin', signOut: '/auth/signout', error: '/auth/error', }, });

Add the relevant auth tokens from your provider of your choosing, here google.

GOOGLE_ID=your-google-client-id GOOGLE_SECRET=your-ggoogle-client-secret

Implementing the SignOut :

import { useEffect } from 'react'; import { signOut } from 'next-auth/client'; import { useRouter } from 'next/router'; const SignOut = () => { const router = useRouter(); useEffect(() => { // Sign out the user and redirect to the homepage signOut({ redirect: false }).then(() => router.push('/')); }, [router]); return ( <div> <h1>Signing you out...</h1> <p>Please wait.</p> </div> ); }; export default SignOut;

Implementing the Error component :

import { useRouter } from 'next/router'; const Error = () => { const router = useRouter(); const { error } = router.query; return ( <div> <h1>Error</h1> <p>Sorry, an error occurred: {error}</p> <button onClick={() => router.push('/')}>Go back to Home</button> </div> ); }; export default Error;

Further reading:

JWT authentication: Best practices and when to use it

Use cases for Auth.js

Auth.js provides an easy way to handle authentication in any web application, but it’s important to understand whether Auth.js is the right tool for your specific project. It’s particularly useful if:

  • You’re starting a new Next.js web application. Since Auth.js was originally designed for Next apps, it can give you a solid base for handling authentication out of the box
  • Your user base is most likely to grow with time, and your app requires a scalable authentication solution that can handle growing complexity
  • You need one of its several ready-made authentication methods, such as email/password sign-in and OAuth providers like Google or GitHub, saving development time

However, Auth.js might not be a suitable solution for you if:

  • Your application requires you to customize the authentication flows
  • Your project is built on older technology or frameworks outside of Next.js, Express, SvelteKit, and Quik. In such a case, Auth.js might be very difficult for you to implement

Conclusion

Auth.js handles user authentication in any JavaScript application more securely and flexibly. It supports a lot of authentication providers, manages user sessions, and even lets you use custom callbacks, making it an ideal solution for a new or existing project.

Also, I strongly believe that with its actively growing community, some of the challenges and concerns raised by some developers about the poor documentation and migration guide will be sorted out and things will improve.

Web Bulletin ™