Implementing Passwordless Login in a Next.js 13 Project with NextAuth.js and Prisma

passwordless
nextjs
nextauth
prisma
Passwordless Login in NextJs 13 cover image

This article will delve into the steps needed to implement passwordless authentication in a Next.js project using the NextAuth.js library. Additionally, we will be utilizing Prisma as our database adapter to achieve this.

Passwordless authentication is an innovative approach that eliminates the need for traditional username and password combinations. Instead, it offers a more secure and user-friendly authentication experience by leveraging alternative methods, such as email magic links or one-time codes sent via SMS.

Next.js is a popular React framework for building web applications, known for its simplicity and efficiency. We can easily incorporate passwordless authentication into our project by integrating NextAuth.js, an authentication library designed explicitly for Next.js.

Additionally, we will be relying on Prisma as our database adapter. Prisma is an ORM (Object-Relational Mapping) tool that simplifies database interactions by providing a type-safe and auto-generated query builder. It supports multiple databases, including PostgreSQL, MySQL, and SQLite, making it a versatile choice for our authentication implementation.

Throughout this guide, we will provide step-by-step instructions on how to set up and configure passwordless authentication using NextAuth.js in a Next.js project. We will also demonstrate how to integrate Prisma as our database adapter, allowing seamless communication between our application and the database.

We will now explore how to improve the security and user experience of our Next.js application using passwordless authentication and the capabilities of NextAuth.js and Prisma. Let's begin.

What’s passwordless login?

Passwordless login, as the name suggests, is a method of authentication that removes the need for traditional username and password combinations. Instead, it utilizes alternative means of verifying a user's identity, such as email magic links or one-time codes sent via SMS. This approach offers several advantages over traditional login methods. Firstly, it eliminates the risk of password-related vulnerabilities, such as weak passwords or password reuse. Secondly, it simplifies the user experience by removing the need to remember and enter complex passwords.

To implement passwordless login using email magic links or one-time codes, we need an SMTP (Simple Mail Transfer Protocol) server.

An SMTP server is responsible for sending emails over the Internet. In the context of passwordless authentication, the server sends the magic links or one-time codes to the user's registered email address. When a user initiates the login process, an email containing a unique link or code is generated and sent to the user. The user can then click on the link or enter the code to complete the authentication process. The SMTP server acts as the intermediary between the application and the user's email service, ensuring authentication messages' secure and reliable delivery. By utilizing an SMTP server, we can effectively implement passwordless login and provide a seamless authentication experience for our users.

Let's get started!

First, we need to generate a fresh new Next.js project. To do this, use the following command:

npx create-next-app@latest

Generating a new NextJS project

Once you have generated the fresh new Next.js project, you can navigate to the newly created project directory.

By changing the directory into the project, you will be able to explore the various folders and files that make up the Next.js project structure.

Project Structure

Understanding the project structure is essential for effective development and organization of your Next.js application. By referring to the official documentation, you can leverage best practices and gain insights into how to structure your code, manage static assets, and create reusable components.

Installing our dependencies

To enable passwordless authentication in our Next.js project using NextAuth.js, we must first install the required dependencies. Run the command yarn add next-auth nodemailer to add both NextAuth.js and nodemailer to our project.

We specifically use nodemailer as it is a popular and versatile module for sending emails in Node.js. It provides a straightforward and reliable way to send the magic links or one-time codes required for passwordless authentication via email.

Next, let's integrate Prisma as our database adapter. Start by installing the required Prisma packages using the command:

yarn add @prisma/client @next-auth/prisma-adapter

These packages will enable seamless communication between our Next.js application and the database. Additionally, we also need to install Prisma as a dev dependency by running:

yarn add prisma --dev

This step ensures we have the necessary tools to work with Prisma and its auto-generated query builder for database interactions.

By installing these dependencies, we set the foundation for implementing passwordless authentication using NextAuth.js and Prisma in our Next.js project.

Setup Prisma

It is necessary to set up Prisma and have access to an SMTP server for email sending to use passwordless authentication in a Next.js project. This tutorial will guide you through using your personal Gmail account to send emails. Follow the steps below for a successful setup.

First, create a "prisma" folder at the root of your project. This folder will house the Prisma-related files and configurations. Then, within the "prisma" folder, create a new file called "schema.prisma" The schema file defines the structure of your database and serves as a blueprint for Prisma's auto-generated code.

If you're new to the concept of a schema, don't worry! A schema specifies your database's tables, fields, relationships, and constraints. To create the schema, you can refer to the official documentation of NextAuth.js and copy the example schema provided there. This schema is a starting point and can be customized to fit your application requirements.

Schema file

Next, create a ".env" file at the root of your project. This file will store your environment variables, including the necessary configurations for your SMTP server. To populate the ".env" file, you can copy the example configurations provided below. Make sure to enter your Gmail account credentials and SMTP server settings in the corresponding fields.

EMAIL_SERVER_USER="YourGmailAddress"
EMAIL_SERVER_PASSWORD="GmailPassOrGeneratedPass"
EMAIL_SERVER_HOST=smtp.gmail.com
EMAIL_SERVER_PORT=587
EMAIL_FROM="noreply@example.com"

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=ThisNeedsToBeSuperSecret

By following these steps, you will have set up Prisma and configured the SMTP server for sending emails using your Gmail account. These preparations are crucial for enabling the passwordless authentication flow in your Next.js project.

Note

You must create an app password if you have enabled Two-Factor Authentication (2FA) for your Google account. An app password is a distinct password that grants access to particular apps or devices without exposing your primary Google account password. Follow the instructions below to generate an app password.

  1. Go to the Google Account settings page by visiting https://myaccount.google.com/.

  2. Navigate to the "Security" tab.

  3. Look for the "2FA" section, scroll down and select "App Passwords".

Google Account Security

Google Account Security

  1. You might be prompted to enter your Google account password again for security verification.

  2. Under the "Select app" dropdown, choose "Mail" or "Other (Custom name)".

  • If "Mail" option is available, select it.

  • If "Mail" option is not available, choose "Other (Custom name)" and provide a custom name for identification.

  1. Click on the "Generate" or "Generate Password" button.

  2. Google will generate a unique app password for you. Make a note of this password, as we will be using this one in our application for sending emails.

  3. Use this generated app password in your Next.js application's SMTP server configuration. Replace your regular Gmail account password with this app password.

This ensures that even with 2FA enabled, your application can securely send emails using your Gmail account.

PostgreSQL using Supabase

Before we can proceed, we need to ensure that the database for our project is functioning correctly. For this demo, we recommend using the Supabase PostgreSQL database. To get started with a Supabase project and obtain the PostgreSQL connection URL, follow these steps:

  1. Go to supabase.io and sign in to your account or create a new one if you don't have one.

  2. Once you're logged in, you'll be directed to the Supabase dashboard. Click on "Create New Project" to start a new project.

  3. Name your project and select the region closest to your current location. Remember your password, you'll need it later.

  4. When you've created the project, you'll be taken to the project dashboard. Click "Database" on the left sidebar to access the database settings.

  5. In the "Database" section, you'll find the PostgreSQL connection URL. This URL contains all the necessary information to connect to your Supabase project's database, such as the host, port, database name, username, and password. It will be displayed in the format: postgres://<username>:<password>@<host>:<port>/<database>

Postgresql connection string

  1. Copy the PostgreSQL connection URL and keep it secure. You'll need it to establish a connection between your application and the Supabase database.
    // .env
    
    DATABASE_URL=postgresql://postgres:[Password]@db.ixjsisbwdafsjvgifliu.supabase.co:5432/postgres
    ```

Now, let's ensure that we generate our Prisma client by running the following command: `npx prisma generate`.

The Prisma Client is a database client automatically generated based on your schema. By default, the Prisma Client is generated into the `node_modules/.prisma/client` folder, but you can [specify a custom location if needed](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/generating-prisma-client#using-a-custom-output-path).

Next, we will proceed to create our initial migration. Run the following command: `npx prisma migrate dev`. You can give each migration a descriptive name.

In Prisma, a migration is a method used to manage adjustments to your database schema as time progresses. It lets you modify your database structure without losing any pre-existing data. These migrations are crucial as they ensure that your database schema aligns with your application's needs as they change. With Prisma's migration tool, you can conveniently version, apply, and revert these changes, simplifying teamwork and maintaining a uniform database schema across various environments.

Now, if we check our database, we will be able to see the changes from our initial migration reflected in the database section.

By performing the initial migration, we have applied the modifications to our database schema as defined in the migration script.

![Database Tables after Migration](https://drive.google.com/uc?export=view&id=1PZ6ban5h4VZs3UHQoJS_5kNYkhqs-MAx)

### Setting up NextAuthJS with Prisma Adapter

In a Next.js application, NextAuthJS uses the catch-all route, also known as the wildcard or fallback route, to manage authentication requests. This dynamic route is defined using the file-based routing system in Next.js.

Create a folder named "**api**" inside your "**app**" directory. Within the "**api**" folder, create an "**auth**" folder. Inside the "**auth**" folder, create a catch-all route called "**[...nextauth]**" as a folder. Lastly, create a "**route.ts**" file inside the catch-all route folder and add the following code.

```jsx
// app/api/auth/[...nextauth]/route.ts
import { PrismaAdapter } from '@next-auth/prisma-adapter';
import { PrismaClient } from '@prisma/client';
import NextAuth from 'next-auth';
import EmailProvider from 'next-auth/providers/email';

const prisma = new PrismaClient();

export const authOptions = {
  adapter: PrismaAdapter(prisma),
  providers: [
    EmailProvider({
      server: {
        host: process.env.EMAIL_SERVER_HOST,
        port: process.env.EMAIL_SERVER_PORT,
        auth: {
          user: process.env.EMAIL_SERVER_USER,
          pass: process.env.EMAIL_SERVER_PASSWORD,
        },
      },
      from: process.env.EMAIL_FROM,
    }),
  ]
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST };

In the catch-all route file, we import the NextAuthJS library and set up the authentication options, providers, and configurations. NextAuthJS handles the parsing of incoming requests, identifies the necessary authentication action, and executes the appropriate logic according to the specified options.

The provided code sets up NextAuthJS with the Prisma adapter for authentication using an email provider. Let’s explain each statement:

  1. Imports:
  • PrismaAdapter and PrismaClient are imported from @next-auth/prisma-adapter and @prisma/client, respectively. These are used to integrate NextAuthJS with Prisma.

  • NextAuth is imported from next-auth and is the main library for handling authentication in Next.js applications.

  • EmailProvider is imported from next-auth/providers/email and is used as a provider for email-based authentication.

  1. Prisma Setup:
  • An instance of PrismaClient is created using new PrismaClient(). This allows communication with the Prisma ORM and the underlying database.
  1. Authentication Options:
  • authOptions is an object that defines the configuration for authentication in NextAuthJS.

  • The adapter property is set to PrismaAdapter(prisma), which connects NextAuthJS with Prisma using the PrismaAdapter.

  • The providers array contains a single provider, EmailProvider. It is configured with the necessary email server details and the from email address.

  1. NextAuth Handler:
  • The NextAuth function is called with authOptions as an argument, creating an authentication handler.

  • The resulting handler is assigned to the handler variable.

  1. Export:
  • handler is exported as GET and POST to support both HTTP GET and POST requests.

Now, let's run our server and test the functionality. First, start the development server by running yarn dev. Next, open your browser and visit localhost:3000 to see the application in action.

To test the authentication functionality, visit localhost:3000/api/auth/signin. Here, you will experience the magic of NextAuthJS. The provided template included with NextAuthJS enables a passwordless sign-in process. To try it out, enter a valid email address.

Passwordless Signin Input

Once you submit the email, NextAuthJS will handle the behind-the-scenes process. First, it will generate and send an email containing a unique sign-in link to the provided email address. This link serves as a secure authentication token for the user. Then, when the user clicks on the link, NextAuthJS will validate the token and authenticate the user.

Signin Email

This passwordless login feature enhances security and user experience by eliminating the need for passwords. Users can quickly and securely access their accounts by simply clicking on the link received via email. It streamlines the login process and reduces the risk of password-related vulnerabilities.

When a user clicks on the sign-in email generated by NextAuthJS and gets authenticated, several actions take place behind the scenes to facilitate a seamless login experience.

1. Email Link Validation: When the user clicks on the sign-in link, NextAuthJS validates the authentication token embedded in the link. This token ensures the security and integrity of the authentication process.

2. Authentication Process: Upon successful token validation, NextAuthJS identifies the user and completes the authentication process. It verifies the user's identity based on the provided token and any additional authentication factors configured, such as multi-factor authentication.

3. Session Creation: After successful authentication, NextAuthJS creates a session for the user. A session is a persistent state that represents the user's authentication status and allows them to access protected resources without having to re-authenticate for subsequent requests.

4. Cookies: NextAuthJS sets secure HTTP-only cookies in the user's browser to manage the session. These cookies play a crucial role in maintaining the user's authenticated state across multiple requests. The cookies typically include a session cookie and optionally a refresh token cookie, depending on the authentication configuration.

Cookies Set By NextAuthJS

  1. Session Cookie: The session cookie contains a session identifier (e.g., a randomly generated string) that uniquely identifies the user's session. It helps NextAuthJS associate subsequent requests with the correct session and user.

  2. CSRF Token Cookie: NextAuthJS sets a CSRF (Cross-Site Request Forgery) token cookie to protect against CSRF attacks. The CSRF token is a unique value generated by NextAuthJS and stored in the cookie. It is used to validate and verify the authenticity of subsequent requests made by the user. When the user submits forms or performs sensitive actions, the CSRF token is included in the request headers or body to ensure that the request originated from the authenticated user's session and not from a malicious source.

  3. Callback URL Cookie: NextAuthJS sets a callback URL cookie to store the original URL that the user was trying to access before being redirected to the authentication flow. This cookie helps NextAuthJS redirect the user back to the desired page after successful authentication. It ensures a smooth user experience by seamlessly returning the user to their intended destination instead of a generic landing page.

By using secure HTTP-only cookies, NextAuthJS ensures that the authentication state remains secure and tamper-proof. The cookies are encrypted, preventing unauthorized access or modification by malicious actors.

Great job on successfully integrating NextAuthJS with Prisma adapter into your Next.js application! With the ease and adaptability provided by NextAuthJS, you now have a reliable authentication system.

Check out the GitHub repository linked below for the code used in this guide: https://github.com/codelabsacademy/next-auth-guide.

But why stop here? If you're passionate about web development and eager to enhance your skills, consider applying for our web development bootcamp. Our bootcamp offers a comprehensive learning experience, equipping you with the knowledge and practical skills necessary to excel in the dynamic world of web development.

By joining our bootcamp, you'll gain hands-on experience with cutting-edge technologies, work on real-world projects, and receive personalized guidance from industry experts. Whether you're a beginner or an experienced developer, our program is designed to take your web development skills to the next level.

Don't miss this opportunity to accelerate your web development journey. Apply for our web development bootcamp today and unlock your full potential in the exciting field of web development. Together, let's build amazing digital experiences and shape the future of the web.


Career Services background pattern

Career Services

Contact Section background image

Let’s stay in touch

Code Labs Academy © 2024 All rights reserved.