Skip to main content

How to Authenticate Users with RainbowKit

Before Starting

You can start this tutorial if you already have a NextJS dapp with MetaMask sign-in functionality.

RainbowKit Installation

npm install @rainbow-me/rainbowkit

RainbowKit Configuration

Modify pages/_app.jsx:

import { createClient, configureChains, WagmiConfig } from "wagmi";
import { publicProvider } from "wagmi/providers/public";
import { mainnet } from "wagmi/chains";
import { SessionProvider } from "next-auth/react";
import { getDefaultWallets, RainbowKitProvider } from "@rainbow-me/rainbowkit";
import "@rainbow-me/rainbowkit/styles.css";

const { provider, webSocketProvider, chains } = configureChains(
[mainnet],
[publicProvider()]
);

const { connectors } = getDefaultWallets({
appName: "My RainbowKit App",
chains,
});

const client = createClient({
provider,
webSocketProvider,
autoConnect: true,
// added connectors from rainbowkit
connectors,
});

// added RainbowKitProvider wrapper
function MyApp({ Component, pageProps }) {
return (
<WagmiConfig client={client}>
<SessionProvider session={pageProps.session} refetchInterval={0}>
<RainbowKitProvider chains={chains}>
<Component {...pageProps} />
</RainbowKitProvider>
</SessionProvider>
</WagmiConfig>
);
}

export default MyApp;

Authentication with RainbowKit

The logic we're achieving works as this. A user connects his wallet using ConnectButton from rainbowkit. Once the wallet is connected, we get address and chain from the following wagmi hooks: useAccount() and useNetwork(). In case the user is not authenticated, we will start the authentication flow (request and sign message).

  1. Open the pages/signin.jsx file and replace the old Authenticate via MetaMask button with <ConnectButton /> from @rainbow-me/rainbowkit:
import { ConnectButton } from '@rainbow-me/rainbowkit';
...

return (
<div>
<h3>Web3 Authentication</h3>
<ConnectButton />
</div>
);
...
  1. Edit handleAuth() and move it under useEffect():
...
useEffect(() => {
const handleAuth = async () => {
const { message } = await requestChallengeAsync({
address: address,
chainId: chain.id,
});

const signature = await signMessageAsync({ message });

// redirect user after success authentication to '/user' page
const { url } = await signIn("moralis-auth", {
message,
signature,
redirect: false,
callbackUrl: "/user",
});
/**
* instead of using signIn(..., redirect: "/user")
* we get the url from callback and push it to the router to avoid page refreshing
*/
push(url);
};
if (status === "unauthenticated" && isConnected) {
handleAuth();
}
}, [status, isConnected]);
...
  1. Update missing imports and add new hooks. This is the final code of pages/signin.jsx:
import { useRouter } from "next/router";
import { useAuthRequestChallengeEvm } from "@moralisweb3/next";
import { ConnectButton } from "@rainbow-me/rainbowkit";
import { signIn, useSession } from "next-auth/react";
import { useAccount, useSignMessage, useNetwork } from "wagmi";
import { useEffect } from "react";

function SignIn() {
const { isConnected, address } = useAccount();
const { chain } = useNetwork();
const { status } = useSession();
const { signMessageAsync } = useSignMessage();
const { push } = useRouter();
const { requestChallengeAsync } = useAuthRequestChallengeEvm();

useEffect(() => {
const handleAuth = async () => {
const { message } = await requestChallengeAsync({
address: address,
chainId: chain.id,
});

const signature = await signMessageAsync({ message });

// redirect user after success authentication to '/user' page
const { url } = await signIn("moralis-auth", {
message,
signature,
redirect: false,
callbackUrl: "/user",
});
/**
* instead of using signIn(..., redirect: "/user")
* we get the url from callback and push it to the router to avoid page refreshing
*/
push(url);
};
if (status === "unauthenticated" && isConnected) {
handleAuth();
}
}, [status, isConnected]);

return (
<div>
<h3>Web3 Authentication</h3>
<ConnectButton />
</div>
);
}

export default SignIn;

Testing the RainbowKit Connector

Visit http://localhost:3000/signin to test authentication.

  1. Click on Connect Wallet:

Sign In Page

  1. Select and connect a wallet you want to use for authentication from the RainbowKit modal:

RainbowKit Modal

  1. Sign the message:

Signing the Message with MetaMask

  1. After successful authentication, you will be redirected to the /user page:

User Page

  1. Visit http://localhost:3000/user to test the user session's functionality:
  • When a user is authenticated, we show the user's info on the page.
  • When a user is not authenticated, we redirect to the /signin page.
  • When a user is authenticated, we show the user's info on the page, even refreshing after the page. (Explanation: After Web3 wallet authentication, the next-auth library creates a session cookie with an encrypted JWT [JWE] stored inside. It contains session info [such as an address and signed message] in the user's browser.)