{"id":13632274,"url":"https://github.com/thirdweb-example/nft-gated-website","last_synced_at":"2025-04-06T18:14:51.200Z","repository":{"id":37946765,"uuid":"479490382","full_name":"thirdweb-example/nft-gated-website","owner":"thirdweb-example","description":"Restrict access to content based on the ownership of an NFT","archived":false,"fork":false,"pushed_at":"2024-05-28T20:05:54.000Z","size":498,"stargazers_count":163,"open_issues_count":0,"forks_count":126,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-30T15:11:14.384Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://nft-gated-website.thirdweb-example.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thirdweb-example.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-08T17:59:57.000Z","updated_at":"2024-12-03T14:26:09.000Z","dependencies_parsed_at":"2023-02-19T04:31:11.867Z","dependency_job_id":"9ee7c635-32a7-496a-a54d-63fad8540d0f","html_url":"https://github.com/thirdweb-example/nft-gated-website","commit_stats":null,"previous_names":["thirdweb-example/token-gated-website"],"tags_count":0,"template":true,"template_full_name":"thirdweb-example/cra-javascript-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fnft-gated-website","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fnft-gated-website/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fnft-gated-website/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fnft-gated-website/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thirdweb-example","download_url":"https://codeload.github.com/thirdweb-example/nft-gated-website/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247526764,"owners_count":20953143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T22:02:58.460Z","updated_at":"2025-04-06T18:14:51.182Z","avatar_url":"https://github.com/thirdweb-example.png","language":"TypeScript","readme":"\u003e [!Important]  \n\u003e This repository is outdated and no longer maintained. But we have something better for you!\n\u003e\n\u003e Head over to this new repository: [gated-site-example](https://github.com/thirdweb-example/gated-site-example)\n\u003e \n\u003e The idea is that, once you have got the user's wallet on the server-side, the use cases are not limited to just token-balance checking, you can basically do anything you want.\n\u003e \n\n\u003e [!Important]  \n\u003e This repository is referencing the `mumbai` chain.\n\u003e \n\u003e `Mumbai` [is deprecated since 08/04/2024](https://blog.thirdweb.com/deprecation-of-mumbai-testnet/), meaning the code in this repository will no longer work out of the box.\n\u003e\n\u003e You can still use this repository, however you will have to switch any references to `mumbai` to another chain.\n\n# Token Gated Website\n\nThis project demonstrates how you can restrict content on your website to only those users who own a token of your choice (any ERC-20, ERC-721 or ERC-1155).\n\nYou can use any token you like regardless if it's deployed using thirdweb or not. However, if the contract wasn't deployed on thirdweb initially, make sure you import the contract on the thirdweb dashboard.\n\n## Installation\n\nInstall the template with [thirdweb create](https://portal.thirdweb.com/cli/create)\n\n```bash\nnpx thirdweb create --template nft-gated-website\n```\n\n## Set up\n\n- Deploy or import an already deployed token contract on thirdweb dashboard.\n- Update the information in the [yourDetails.js](./const/yourDetails.js) file to use your contract address and auth domain name.\n\n### Environment Variables\n\nTo run this project, you will need to add the following environment variables to your .env file:\n\n```bash\nTHIRDWEB_AUTH_PRIVATE_KEY=\nNEXT_PUBLIC_TEMPLATE_CLIENT_ID=\nTW_SECRET_KEY=\n```\n\n- Generate your `TW_SECRET_KEY` and `NEXT_PUBLIC_TEMPLATE_CLIENT_ID` via thirdweb's [dashboard](https://thirdweb.com/create-api-key).\n- For `THIRDWEB_AUTH_PRIVATE_KEY` export your wallet private key from your wallet.\n\n### Run Locally\n\nInstall dependencies:\n\n```bash\n  yarn\n```\n\nStart the server:\n\n```bash\n  yarn start\n```\n\n## How It Works\n\nUsing [Auth](https://portal.thirdweb.com/auth), we can verify a user's identity on the server-side, by asking them to sign a message and verify they own the wallet they claim to be, and validating the signature.\n\nWhen we verified the user's identity on the server-side, we check their wallet to see if they have an NFT from our collection. We can then serve different content and restrict what pages they can access based on their NFT balance.\n\n```jsx\n// This is the chain your dApp will work on.\nconst activeChain = \"mumbai\";\n\nfunction MyApp({ Component, pageProps }) {\n  return (\n    \u003cThirdwebProvider\n      activeChain={activeChain}\n      authConfig={{\n        domain: domainName,\n        authUrl: \"/api/auth\",\n      }}\n    \u003e\n      \u003cHead\u003e\n        \u003ctitle\u003eNFT Gated Website\u003c/title\u003e\n        \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\n        \u003cmeta\n          name=\"description\"\n          content=\"Learn how to use the thirdweb Auth SDK to create an NFT Gated Website\"\n        /\u003e\n      \u003c/Head\u003e\n      \u003cComponent {...pageProps} /\u003e\n    \u003c/ThirdwebProvider\u003e\n  );\n}\n\nexport default MyApp;\n```\n\nNext, we need to create a configuration file that contains our wallet's private key (used to generate messages for users to sign) and our site's domain name:\n\nThis file is called `auth.config.js` and is at the root of the project.\n\n```jsx\nimport { ThirdwebAuth } from \"@thirdweb-dev/auth/next\";\nimport { PrivateKeyWallet } from \"@thirdweb-dev/auth/evm\";\nimport { domainName } from \"./const/yourDetails\";\n\nexport const { ThirdwebAuthHandler, getUser } = ThirdwebAuth({\n  domain: domainName,\n  wallet: new PrivateKeyWallet(process.env.THIRDWEB_AUTH_PRIVATE_KEY || \"\"),\n});\n```\n\nFinally, we have a [catch-all API route](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes) called `pages/api/auth/[...thirdweb].js`, which exports the `ThirdwebAuthHandler` to manage all of the required auth endpoints like `login` and `logout`.\n\n```jsx\nimport { ThirdwebAuthHandler } from \"../../../auth.config\";\n\nexport default ThirdwebAuthHandler();\n```\n\n## Restricting Access\n\nTo begin with, the user will reach the website with no authentication.\n\nWhen they try to access the restricted page (the `/` route), we use [getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props) to check two things:\n\n1. If the user is currently authenticated (using `getUser`).\n2. If the user's wallet balance is greater than `minTokensRequired` provided in `yourDetails.js` of the NFTs in our NFT collection.\n\nIf either of these checks is `false`, we redirect the user to the `/login` page before they are allowed to access the restricted page.\n\nLet's break that down into steps:\n\n### Setting Up the Auth SDK\n\nInside the [\\_app.jsx](./pages/_app.jsx) file, we configure the Auth SDK in the `ThirdwebProvider` component that wraps our application, allowing us to use the hooks of the SDK throughout our application:\n\n### Checking For Authentication Token\n\nFirst, we check if this user has already been authenticated.\n\nIf this is the first time the user has visited the website, they will not have an `access_token` cookie.\n\n```js\n// This gets called on every request\nexport async function getServerSideProps(context) {\n  const user = await getUser(context.req);\n\n  if (!user) {\n    return {\n      redirect: {\n        destination: \"/login\",\n        permanent: false,\n      },\n    };\n  }\n\n  // ...\n}\n```\n\nIf the user is not authenticated, then we don't check the user's wallet balance; we just immediately redirect them to the `/login` page.\n\nIf there _is_ a detected user from `getUser`, we can then check their balance.\n\n### Checking Wallet Balance\n\nNow we're ready to check the user's wallet balance.\n\nTo do this, we have created a utility function called [checkBalance](./util/checkBalance.js) that we can use to check the user's balance for a given NFT.\n\n```js\nimport { isFeatureEnabled } from \"@thirdweb-dev/sdk\";\nimport {\n  contractAddress,\n  erc1155TokenId,\n  minimumBalance,\n} from \"../const/yourDetails\";\n\nexport default async function checkBalance(sdk, address) {\n  const contract = await sdk.getContract(\n    contractAddress // replace this with your contract address\n  );\n\n  let balance;\n\n  if (isFeatureEnabled(contract.abi, \"ERC1155\")) {\n    balance = await contract.erc1155.balanceOf(address, erc1155TokenId);\n  } else if (isFeatureEnabled(contract.abi, \"ERC721\")) {\n    balance = await contract.erc721.balanceOf(address);\n  } else if (isFeatureEnabled(contract.abi, \"ERC20\")) {\n    balance = (await contract.erc20.balanceOf(address)).value;\n    return balance.gte((minimumBalance * 1e18).toString());\n  }\n\n  // gte = greater than or equal to\n  return balance.gte(minimumBalance);\n}\n```\n\nThis function will check the type of contract being used, check the balance accordingly and returns true or false that we can store in a variable:\n\n```js\nconst hasNft = await checkBalance(sdk, address);\n```\n\nHere's our final check, if the user has a `balance` of `0`, then we redirect them to the `/login` page.\n\n```js\n// If they don't have an NFT, redirect them to the login page\nif (!hasNft) {\n  return {\n    redirect: {\n      destination: \"/login\",\n      permanent: false,\n    },\n  };\n}\n```\n\nIf the user gets past these checks, then we allow them to view the restricted page.\n\n```js\n// Finally, return the props\nreturn {\n  props: {},\n};\n```\n\n## Signing In\n\nWe've now successfully restricted access to our home page, now let's explore the `/login` page.\n\nWe use the `ConnectWallet` component to handle the connection to the user's wallet, signing in, and signing out.\n\n```js\n\u003cConnectWallet /\u003e\n```\n\n## Additional Resources\n\n- [Documentation](https://portal.thirdweb.com)\n- [Templates](https://thirdweb.com/templates)\n- [Video Tutorials](https://youtube.com/thirdweb_)\n- [Blog](https://blog.thirdweb.com)\n\n## Contributing\n\nContributions and [feedback](https://feedback.thirdweb.com) are always welcome!\n\nPlease visit our [open source page](https://thirdweb.com/open-source) for more information.\n\n## Need help?\n\nFor help, join the [discord](https://discord.gg/thirdweb) or visit our [support page](https://support.thirdweb.com).\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdweb-example%2Fnft-gated-website","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthirdweb-example%2Fnft-gated-website","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdweb-example%2Fnft-gated-website/lists"}