{"id":16212026,"url":"https://github.com/mandeepsinghmar/project_course_thirdweb","last_synced_at":"2025-04-07T21:43:04.453Z","repository":{"id":237447897,"uuid":"533256527","full_name":"Mandeepsinghmar/project_course_thirdweb","owner":"Mandeepsinghmar","description":null,"archived":false,"fork":false,"pushed_at":"2022-10-05T09:01:06.000Z","size":745,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-13T23:16:04.737Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"project-course-thirdweb.vercel.app","language":"JavaScript","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/Mandeepsinghmar.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-09-06T09:40:30.000Z","updated_at":"2023-04-18T06:50:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"1d7117ed-a69f-4c88-959a-d394add040bd","html_url":"https://github.com/Mandeepsinghmar/project_course_thirdweb","commit_stats":null,"previous_names":["mandeepsinghmar/project_course_thirdweb"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandeepsinghmar%2Fproject_course_thirdweb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandeepsinghmar%2Fproject_course_thirdweb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandeepsinghmar%2Fproject_course_thirdweb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Mandeepsinghmar%2Fproject_course_thirdweb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Mandeepsinghmar","download_url":"https://codeload.github.com/Mandeepsinghmar/project_course_thirdweb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247736767,"owners_count":20987692,"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-10-10T10:50:00.513Z","updated_at":"2025-04-07T21:43:04.409Z","avatar_url":"https://github.com/Mandeepsinghmar.png","language":"JavaScript","readme":"# NFT Gated Website\n\nThis project demonstrates how you can restrict content on your website to only those users who own an NFT from your collection.\n\nWe use an [Edition Drop](https://portal.thirdweb.com/pre-built-contracts/edition-drop) contract to enable users to claim one of the NFTs, and serve users\nthe restricted content if they have at least one of the NFTs claimed.\n\n## Tools:\n\n- [React SDK](https://docs.thirdweb.com/react): To access the connected wallet, switch the user's network, and claim an NFT from our Edition Drop collection.\n- [Auth](https://portal.thirdweb.com/building-web3-apps/authenticating-users): To ask users to sign a message and verify they own the wallet they claim to be, while on the server-side.\n\n## Using This Template\n\nCreate a project using this example:\n\n```bash\nnpx thirdweb create --template nft-gated-website\n```\n\n- Create an [Edition Drop](https://thirdweb.com/contracts/new/pre-built/drop/edition-drop) contract using the dashboard.\n- Update the information in the [yourDetails.js](./const/yourDetails.js) file to use your contract address and auth domain name.\n- Add your wallet's private key as an environment variable in a `.env.local` file called `PRIVATE_KEY`:\n\n```text title=\".env.local\"\nTHIRDWEB_AUTH_PRIVATE_KEY=your-wallet-private-key\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\nfunction MyApp({ Component, pageProps }) {\n  return (\n    \u003cThirdwebProvider\n      desiredChainId={activeChainId}\n      authConfig={{\n        domain: domainName, // This can be any value. e.g. \"thirdweb.com\"\n        authUrl: \"/api/auth\",\n        loginRedirect: \"/\",\n      }}\n    \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 { domainName } from \"./const/yourDetails\";\n\nexport const { ThirdwebAuthHandler, getUser } = ThirdwebAuth({\n  privateKey: process.env.THIRDWEB_AUTH_PRIVATE_KEY || \"\",\n  domain: domainName,\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 `0` 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 { contractAddress } from \"../const/yourDetails\";\n\nexport default async function checkBalance(sdk, address) {\n  const editionDrop = sdk.getEditionDrop(\n    contractAddress // replace this with your contract address\n  );\n\n  // Here, \"0\" is checking the balance of token ID 0.\n  const balance = await editionDrop.balanceOf(address, 0);\n\n  // gt = greater than\n  return balance.gt(0);\n}\n```\n\nThis function 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\nFirst, we ask the user to connect their wallet with our `useMetaMask` hook:\n\n```js\nconst connectWithMetamask = useMetamask();\n\n// ...\n\n\u003cbutton onClick={() =\u003e connectWithMetamask()}\u003eConnect Wallet\u003c/button\u003e;\n```\n\nOnce an `address` is detected from the `useAddress` hook, we show them the `Sign In` button:\n\n```js\n{\n  address ? (\n    \u003c\u003e\n      \u003cbutton onClick={signIn}\u003eSign In\u003c/button\u003e\n    \u003c/\u003e\n  ) : (\n    \u003c\u003e\n      \u003cbutton onClick={() =\u003e connectWithMetamask()}\u003eConnect Wallet\u003c/button\u003e\n    \u003c/\u003e\n  );\n}\n```\n\nThe `Sign In` button calls the `login` function that we're importing from the Auth SDK:\n\n```jsx\nconst login = useLogin();\n```\n\nInside the [\\_app.jsx](./page/_app.jsx) file, we configured the redirect users to the `/` route after they successfully sign in:\n\n```jsx\nfunction MyApp({ Component, pageProps }) {\n  return (\n    \u003cThirdwebProvider\n      desiredChainId={activeChainId}\n      authConfig={{\n        domain: domainName,\n        authUrl: \"/api/auth\",\n        loginRedirect: \"/\", // redirect users to the home page after they successfully sign in\n      }}\n    \u003e\n      \u003cComponent {...pageProps} /\u003e\n    \u003c/ThirdwebProvider\u003e\n  );\n}\n\nexport default MyApp;\n```\n\nOnce the user has authenticated (signed the message), they are redirected to the home page `/`, and the `getServersideProps` logic runs again. Checking to see if they have an NFT balance greater than `0`.\n\n### Sign Out\n\nFinally, on the home page, we have a `Sign Out` button for the user, which calls the `logout` function that we imported from the Auth SDK, and sends the user back to the `/login` route.\n\n```jsx\nconst logout = useLogout();\n```\n\n## Join our Discord!\n\nFor any questions, suggestions, join our discord at [https://discord.gg/thirdweb](https://discord.gg/thirdweb).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandeepsinghmar%2Fproject_course_thirdweb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmandeepsinghmar%2Fproject_course_thirdweb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandeepsinghmar%2Fproject_course_thirdweb/lists"}