23
loading...
This website collects cookies to deliver better user experience
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).
NextAuth
and Magic
packagesyarn add next-auth magic-sdk @magic-sdk/admin
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: [
Providers.Credentials({
name: 'Magic Link',
credentials: {
didToken: { label: 'DID Token', type: 'text' },
},
async authorize({ didToken }, req) {
// validate magic DID token
magic.token.validate(didToken);
// fetch user metadata
const metadata = await magic.users.getMetadataByToken(didToken);
// return user info
return { ...metadata };
},
}),
],
});
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', {
didToken,
callbackUrl: router.query['callbackUrl'] as string,
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email', { required: true })} placeholder="[email protected]" />
<button type="submit">Sign in</button>
</form>
);
}
.env
file with your public/secret keys found on the Magic dashboard.// .env
NEXT_PUBLIC_MAGIC_PK=pk_live_XXXXXXX
MAGIC_SK=sk_live_XXXXXXX
Magic
and have NextAuth.js
handle the rest!