How to set up NextAuth with Crossmint’s Wallets as a Service

Crossmint
3 min readNov 16, 2023

Estimated integration time: 30 minutes

This guide will show you how to integrate NextAuth and Crossmint in just a few minutes. No pre-requisites.

At the end of this guide you will be able to:

  • Allow users to sign up to your website using any social log-in method.
  • Create invisible wallets for them upon sign-up.

Setting up a Crossmint account

  1. Create a Crossmint production (https://www.crossmint.com/console) or staging account (https://staging.crossmint.com/console).
  2. On the console, get your Wallet API keys (server-side). You will need at least wallets.create, wallets.read, and wallets:nfts.read. Also grab wallets:nfts.transfer if you want to allow users to transfer their NFTs to other wallets.
  3. Copy your API key (secret) and project ID

Setting up a NextAuth account

First, import NextAuth into your database by following this guide.

Once you’re done, you must enable callbacks so you can create and fetch wallets for a user after they’ve managed to successfully authenticate.

In your […nextauth].js file, ensure jwt is enabled in the session and add 3 callbacks (signIn, jwt, and session).

Here’s some sample code of the […nextauth].js file which implements Google sign-in:

import NextAuth from “next-auth”
import GoogleProvider from “next-auth/providers/google”
import { WalletService } from “@/services/wallets”;

export const authOptions = {
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET
})
],
session: {
jwt: true,
},
callbacks: {
async signIn({ user, isNewUser }) {
if (isNewUser) {
console.info(`NextAuth: created user ${user.id}`);
await WalletService.createWallets(user.id);
console.info(`NextAuth: initialized wallet for user ${user.id}`);
}

console.info(`NextAuth: fetching wallets for user ${user.id}`);
user.wallets = await WalletService.fetchWallets(user.id);
return true;
},
async jwt({ token, user, account, profile, isNewUser }) {
if (user) {
token.wallets = user.wallets;
}
return token;
},
async session({ session, token }) {
session.wallets = token.wallets;
return session;
},
}
}

export default NextAuth(authOptions);

We’ll also need to add the wallets service which will be used for creating/fetching the wallets. Here’s our service file which uses 2 API endpoints: Creating a wallet and Fetching your wallets:

export class WalletService {
static async fetchWallets(userId) {
let walletsMap = {};
const existingWallets = await WalletService.#fetchWalletsInternal(userId);
existingWallets.forEach((wallet) => {
const chain = wallet.chain;
const address = wallet.publicKey;
walletsMap[chain] = address;
});
return walletsMap;
}

static async createWallets(userId) {
const url = `${process.env.CROSSMINT_BASEURL}/api/v1-alpha1/wallets`;
const options = WalletService.#createOptions("POST", {
chain: "ethereum",
userId: userId,
});
return WalletService.#fetchWithExceptionHandling(url, options);
}

static async #fetchWalletsInternal(userId) {
const url = new URL(
`${process.env.CROSSMINT_BASEURL}/api/v1-alpha1/wallets`,
);
url.searchParams.append("userId", userId);
const options = WalletService.#createOptions("GET");
return WalletService.#fetchWithExceptionHandling(url, options);
}

static #createOptions(method, body = null) {
return {
method: method,
headers: {
accept: "application/json",
"X-CLIENT-SECRET": process.env.CROSSMINT_X_CLIENT_SECRET,
"X-PROJECT-ID": process.env.CROSSMINT_X_PROJECT_ID,
...(body && { "content-type": "application/json" }),
},
...(body && { body: JSON.stringify(body) }),
};
}

static async #fetchWithExceptionHandling(url, options) {
try {
const response = await fetch(url, options);
return await response.json();
} catch (error) {
console.error("Error whilst fetching", error);
throw new Error("An internal error has occurred");
}
}
}

For this code to run, you will need to set up some environment variables:

CROSSMINT_X_CLIENT_SECRET: API Key from the Crossmint console (step 3 in set up)
CROSSMINT_X_PROJECT_ID: Project ID from the Crossmint console (step 3 in set up)
CROSSMINT_BASEURL: Use either "https://www.crossmint.com" or
"https://staging.crossmint.com", depending on whether you are running in production
or staging

And that’s it! You can retrieve users’ wallets by running:

const { data: session } = useSession();

if (session == null) {
return;
}

const { wallets } = session;

Check Crossmint’s documentation for many more things you can do with Crossmint.

--

--

Crossmint

Crossmint is the leading enterprise provider of infrastructure to build NFT use cases, powering 30,000+ enterprises like Mastercard and Microsoft.