In this guide, we will create a website that restricts content based on owning an NFT using React.
In this guide, we use an Edition Drop, which allows many NFTs to be created from the same asset, which is perfect for a membership card!
Using the template repository
To get started, we can use the CLI to clone a starter kit.
npx thirdweb create --next --js
Setup the ThirdwebProvider
Inside the pages/_app.js
page, we wrap our application in the ThirdwebProvider
component to access all of the React SDK's hooks anywhere in our application.
In this file, we need to configure a desiredChainId
that our project will work on.
For this project, we’ll be using Mumbai
since our Edition Drop contract is on the Mumbai testnet.
import { ChainId, ThirdwebProvider } from "@thirdweb-dev/react";
// This is the chainId your dApp will work on.
const activeChainId = ChainId.Mumbai;
function MyApp({ Component, pageProps }) {
return (
<ThirdwebProvider
desiredChainId={activeChainId}
authConfig={{
domain: domainName,
authUrl: "/api/auth",
loginRedirect: "/",
}}
>
<Component {...pageProps} />
</ThirdwebProvider>
);
}
export default MyApp;
Creating the Auth Config File
Create a new file called auth.config.js
at the root of your project.
Here is where we configure the ThirdwebAuth
object for us to use in our authentication endpoints.
We need to pass two configuration options to the ThirdwebAuth
object:
- Our wallet's
privateKey
, which is used on the server-side to generate signatures for users to sign into the application with. - Our domain name, which can be any value you want, typically the name of your website such as
thirdweb.com
.
import { ThirdwebAuth } from "@thirdweb-dev/auth/next";
export const { ThirdwebAuthHandler, getUser } = ThirdwebAuth({
privateKey: "<your-private-key-here>"
domain: "your-domain-name-here",
});
Learn how to export your private key from your wallet.
Ensure you store and access your private key securely.
- Never commit any file that may contain your private key to your source control.
Auth API Endpoint
Finally, we have a catch-all API route
called pages/api/auth/[...thirdweb].js
, which exports the ThirdwebAuthHandler
to manage all of the required auth endpoints like login
and logout
.
Create a new page inside the pages/api/auth
folder (you'll need to create this) and name it [...thirdweb].js
,
and export the ThirdwebAuthHandler
from this file that we set up in our auth.config.js
file.
import { ThirdwebAuthHandler } from "../../../auth.config";
export default ThirdwebAuthHandler();
Restricting Home Page Access
On the homepage, we run server-side code within getServersideProps
to check:
- The user is authenticated
- The user has an NFT from our collection
If the user isn't authenticated or doesn't have an NFT, they're redirected to the /login
page before they can access
the content of the home page.
Let's set up this home page logic now.
First, we need to import the functionality we're going to be using:
import React from "react";
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import { useLogout } from "@thirdweb-dev/react";
import { getUser } from "../auth.config";
import checkBalance from "../util/checkBalance";
Since our home page is only accessible by authenticated NFT holders, we can show any data here, such as a thank you message
export default function Home() {
const logout = useLogout();
return (
<div>
<h1>Restricted Access Page</h1>
<p>Thanks for being a member of our NFT community!</p>
<button onClick={logout}>Logout</button>
</div>
);
}
Above, we're showing a simple thank you message and a button to logout
, which will sign them out and redirect the user to the /login
page.
Before we reach this point, we'll run logic inside out getServersideProps function, which checks the user's authentication status and their NFT balance.
If they are not authenticated or don't own an NFT, they are redirected back to the /login
page.
// This gets called on every request
export async function getServerSideProps(context) {
const user = await getUser(context.req);
if (!user) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
// Instantiate our SDK
const sdk = ThirdwebSDK.fromPrivateKey(
// Learn more about securely storing your private key: https://portal.thirdweb.com/web3-sdk/set-up-the-sdk/securing-your-private-key
"your-admin-private-key-here"
"mumbai",
);
// Check to see if the user has an NFT
const hasNft = await checkBalance(sdk, user.address);
// If they don't have an NFT, redirect them to the login page
console.log("User", user.address, "doesn't have an NFT! Redirecting...");
if (!hasNft) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
// Finally, return the props
return {
props: {},
};
}
Checking NFT Balance
In the snippet above, we call a utility function called checkBalance
, which checks to see if the user has an NFT from our collection.
import { contractAddress } from "../const/yourDetails";
export default async function checkBalance(sdk, address) {
const editionDrop = sdk.getEditionDrop(
contractAddress, // replace this with your contract address
);
const balance = await editionDrop.balanceOf(address, 0);
// gt = greater than
return balance.gt(0);
}
Great! Now each time a user attempts to reach the /
page, we'll check to see if they have an NFT before allowing them to enter.
Let's create the /login
page now where users can sign into our application with their wallet.
Login Page
Create a new page in the pages
folder called login.jsx
.
This page needs to contain a button that calls the login
function
First, let's import the logic we need for this file:
import {
useAddress,
useMetamask,
useEditionDrop,
useClaimNFT,
useNetwork,
useNetworkMismatch,
useUser,
useLogin,
} from "@thirdweb-dev/react";
import { ChainId } from "@thirdweb-dev/sdk";
import { contractAddress } from "../const/yourDetails";
Beneath the imports, we render some conditional logic based on the address
variable (which detects the connected wallet address to our site).
If there is a connected wallet, we show the Sign In button, which calls the login
function we imported from the useLogin
hook.
This asks the user to sign a message with their wallet to prove their identity,
and redirects them to the URL we configured for the loginRedirect
field in the ThirdwebProvider
; which we set as /
.
This means that after the user approves the message, they will be redirected to the /
page; where they will be checked to see if they have an NFT again!
export default function Login() {
// Wallet & Network Information
const address = useAddress();
const connectWithMetamask = useMetamask();
// Hooks to sign in with ethereum (auth SDK)
const login = useLogin(); // Sign in
return (
<div>
{address ? (
<>
<p>Welcome, {address.slice(0, 6)}...</p>
<button onClick={login}>Sign In</button>
</>
) : (
<>
<button onClick={() => connectWithMetamask()}>Connect Wallet</button>
</>
)}
</div>
);
}
Full Project
You can create a copy of this project from our example repository.
To create a project with all of the code from this guide, you can run:
npx thirdweb create --template nft-gated-website
Join our Discord to stay up to date with the latest updates from the team!