DEV Community

Nick Arciero
Nick Arciero

Posted on

Using NextAuth.js with Magic links

NextAuth.js + Magic

This post is about how to use Magic link authentication with NextAuth.js to enable passwordless authentication in a Next.js app.

While NextAuth.js supports passwordless auth via the Email provider, Magic provides blockchain based security and minimal setup that makes it easy to get up and running (NextAuth.js requires configuring your database for magic email links).


Install the necessary NextAuth and Magic packages

yarn add next-auth magic-sdk @magic-sdk/admin
Enter fullscreen mode Exit fullscreen mode

Step 1

To start, we need to create a custom NextAuth Credentials provider that will validate the Magic login and return the User object.

// src/pages/api/auth/[...nextauth].ts

import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
import { Magic } from '@magic-sdk/admin';

const magic = new Magic(process.env.MAGIC_SK);

export default NextAuth({
  session: {
    jwt: true,
  pages: {
    // override signIn page so we can integrate with Magic
    signIn: '/auth/signin',
  providers: [
      name: 'Magic Link',
      credentials: {
        didToken: { label: 'DID Token', type: 'text' },
      async authorize({ didToken }, req) {
        // validate magic DID token

        // fetch user metadata
        const metadata = await magic.users.getMetadataByToken(didToken);

        // return user info
        return { ...metadata };
Enter fullscreen mode Exit fullscreen mode

Step 2

Next, we need to create a custom signIn page. This page will contain a <form> that captures the user's email and in the onSubmit function will login using the Magic SDK.

Notice in Step 1 how we specified a custom signIn page (/auth/signin). This allows us to build a custom login flow with Magic and then signIn via NextAuth. You can extend this custom signIn page to support social login providers (using Magic or NextAuth).

// src/pages/auth/signin.tsx

import { useRouter } from 'next/router';
import { signIn } from 'next-auth/client';
import { Magic } from 'magic-sdk';
import { useForm } from 'react-hook-form'; // use your form lib of choice here

// magic-sdk is only availabile in the browser
const magic = typeof window !== 'undefined' && new Magic(process.env.NEXT_PUBLIC_MAGIC_PK || 'a');

export default function SignIn() {
  const router = useRouter();
  const { register, handleSubmit } = useForm();

  const onSubmit = async ({ email }) => {
    if (!magic) throw new Error(`magic not defined`);

    // login with Magic
    const didToken = await magic.auth.loginWithMagicLink({ email });

    // sign in with NextAuth
    await signIn('credentials', {
      callbackUrl: router.query['callbackUrl'] as string,

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input {...register('email', { required: true })} placeholder="" />

      <button type="submit">Sign in</button>
Enter fullscreen mode Exit fullscreen mode

Step 3

Make sure to populate your .env file with your public/secret keys found on the Magic dashboard.

// .env

Enter fullscreen mode Exit fullscreen mode

Magic Dashboard Keys

Finishing up

You should now be able to login via Magic and have NextAuth.js handle the rest!

Sign up for Magic using this link to get an additional 3,000 free logins!

Discussion (4)

brn2106 profile image
John T

Hi Nick - this is great. I'm working on a small project and was curious if you had any advice on how I may use Stytch's passwordless email magic links with NextAuth.js - its a similar solution:

I'm working through the credentials provider as well but getting hung up and I'm not sure where exactly - any advice would be greatly appreciated!!

salahcgp profile image
Md Salah Uddin

i tried to use this method, but couldn't make it work. can you provide git link with js extension?

jensiepoo profile image
Jensen Kuo

Will this be able to handle reauthentication with Magic? Since like the session is independent of Magic, but is managed by next-auth.

narciero profile image
Nick Arciero Author

Yes, you can add custom logic to the Provider's authorize function or implement one of next-auth's callbacks depending on what you're trying to achieve.

Might also be worth reading this guide from Magic's docs.