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
- Yarn
- pnpm
npm install @rainbow-me/rainbowkit
yarn add @rainbow-me/rainbowkit
pnpm add @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).
- Open the
pages/signin.jsx
file and replace the oldAuthenticate via MetaMask
button with<ConnectButton />
from@rainbow-me/rainbowkit
:
import { ConnectButton } from '@rainbow-me/rainbowkit';
...
return (
<div>
<h3>Web3 Authentication</h3>
<ConnectButton />
</div>
);
...
- Edit
handleAuth()
and move it underuseEffect()
:
...
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]);
...
- 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.
- Click on
Connect Wallet
:
- Select and connect a wallet you want to use for authentication from the RainbowKit modal:
- Sign the message:
- After successful authentication, you will be redirected to the
/user
page:
- 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.)