├── Part1
├── NFT-ERC721-Sample-Collection-SmartContract.sol
├── README.md
├── components
│ ├── config.js
│ ├── nftabi.json
│ └── web3connect.js
└── pages
│ ├── _app.js
│ ├── api
│ └── hello.js
│ ├── denied.js
│ ├── index.js
│ └── welcome.js
└── README.md
/Part1/NFT-ERC721-Sample-Collection-SmartContract.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT LICENSE
2 |
3 | /*
4 | N2D NFT ERC721 NFT Smart Contract.
5 |
6 | Follow/Subscribe Youtube, Github, IM, Tiktok
7 | for more amazing content!!
8 | @Net2Dev
9 | ███╗░░██╗███████╗████████╗██████╗░██████╗░███████╗██╗░░░██╗
10 | ████╗░██║██╔════╝╚══██╔══╝╚════██╗██╔══██╗██╔════╝██║░░░██║
11 | ██╔██╗██║█████╗░░░░░██║░░░░░███╔═╝██║░░██║█████╗░░╚██╗░██╔╝
12 | ██║╚████║██╔══╝░░░░░██║░░░██╔══╝░░██║░░██║██╔══╝░░░╚████╔╝░
13 | ██║░╚███║███████╗░░░██║░░░███████╗██████╔╝███████╗░░╚██╔╝░░
14 | ╚═╝░░╚══╝╚══════╝░░░╚═╝░░░╚══════╝╚═════╝░╚══════╝░░░╚═╝░░░
15 |
16 | THIS CONTRACT IS AVAILABLE FOR EDUCATIONAL
17 | PURPOSES ONLY. YOU ARE SOLELY REPONSIBLE
18 | FOR ITS USE. I AM NOT RESPONSIBLE FOR ANY
19 | OTHER USE. THIS IS TRAINING/EDUCATIONAL
20 | MATERIAL. ONLY USE IT IF YOU AGREE TO THE
21 | TERMS SPECIFIED ABOVE.
22 | */
23 |
24 |
25 | import "@openzeppelin/contracts/access/Ownable.sol";
26 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
27 |
28 | pragma solidity ^0.8.4;
29 |
30 | contract Collection is ERC721Enumerable, Ownable {
31 |
32 |
33 | using Strings for uint256;
34 | string public baseURI;
35 | string public baseExtension = ".json";
36 | uint256 public maxSupply = 1000;
37 | uint256 public maxMintAmount = 5;
38 | bool public paused = false;
39 |
40 | constructor() ERC721("Net2Dev NFT Collection", "N2D") {}
41 |
42 |
43 | function _baseURI() internal view virtual override returns (string memory) {
44 | return "ipfs://QmYB5uWZqfunBq7yWnamTqoXWBAHiQoirNLmuxMzDThHhi/";
45 |
46 | }
47 |
48 | function mint(address _to, uint256 _mintAmount) public payable {
49 | uint256 supply = totalSupply();
50 | require(!paused);
51 | require(_mintAmount > 0);
52 | require(_mintAmount <= maxMintAmount);
53 | require(supply + _mintAmount <= maxSupply);
54 |
55 | for (uint256 i = 1; i <= _mintAmount; i++) {
56 | _safeMint(_to, supply + i);
57 | }
58 | }
59 |
60 |
61 | function walletOfOwner(address _owner)
62 | public
63 | view
64 | returns (uint256[] memory)
65 | {
66 | uint256 ownerTokenCount = balanceOf(_owner);
67 | uint256[] memory tokenIds = new uint256[](ownerTokenCount);
68 | for (uint256 i; i < ownerTokenCount; i++) {
69 | tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
70 | }
71 | return tokenIds;
72 | }
73 |
74 |
75 | function tokenURI(uint256 tokenId)
76 | public
77 | view
78 | virtual
79 | override
80 | returns (string memory) {
81 | require(
82 | _exists(tokenId),
83 | "ERC721Metadata: URI query for nonexistent token"
84 | );
85 |
86 | string memory currentBaseURI = _baseURI();
87 | return
88 | bytes(currentBaseURI).length > 0
89 | ? string(abi.encodePacked(currentBaseURI, tokenId.toString(), baseExtension))
90 | : "";
91 | }
92 | // only owner
93 |
94 | function setmaxMintAmount(uint256 _newmaxMintAmount) public onlyOwner() {
95 | maxMintAmount = _newmaxMintAmount;
96 | }
97 |
98 | function setBaseURI(string memory _newBaseURI) public onlyOwner() {
99 | baseURI = _newBaseURI;
100 | }
101 |
102 | function setBaseExtension(string memory _newBaseExtension) public onlyOwner() {
103 | baseExtension = _newBaseExtension;
104 | }
105 |
106 | function pause(bool _state) public onlyOwner() {
107 | paused = _state;
108 | }
109 |
110 | function withdraw() public payable onlyOwner() {
111 | require(payable(msg.sender).send(address(this).balance));
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/Part1/README.md:
--------------------------------------------------------------------------------
1 | # Web3-NFT-User-Authentication
2 | ⚡ A very straightfoward guide to authenticate users in NextJS with NFTs.
3 | Block users that aren't holding a specific ERC721 NFT
4 |
5 |
Securing Apps with NFTs
6 |
7 |
8 | ** THE FILES ATTACHED TO THIS REPO ARE FOR EDUCATIONAL PURPOSES ONLY **
9 |
10 | ** NOT FINANCIAL ADVISE **
11 |
12 | ** USE IT AT YOUR OWN RISK** **I'M NOT RESPONSIBLE FOR ANY USE, ISSUES ETC.. **
13 |
14 |
15 | Click for video:
16 |
17 |
18 |
19 |
20 | Steps to use this Repo
21 |
22 |
23 | 1-Create a new NextJS app:
24 |
25 | ```shell
26 | npx create-next-app web3auth
27 | ```
28 |
29 | 2- Install Dependencies:
30 |
31 | ```shell
32 | cd web3auth
33 | npm i ethers web3modal
34 | ```
35 |
36 | 3- Replace all files and folders in your project with the ones attached to this repo.
37 |
38 | Add all files and folders to the root project directory "web3auth", overwrite when prompted.
39 |
40 | 4- Deploy the attached NFT Smart Contract Attached to your favorite testnet
41 |
42 | NFT-ERC721-Sample-Collection-SmartContract.sol
43 |
44 | 5- Mint a couple of NFTs from the smart contract to one wallet.
45 |
46 | 6- Add the NFT Smart Contract address to: components/config.js
47 |
48 | ```shell
49 | export const nftcontract = "REPLACE WITH NFT SMART CONTRACT ADDRESS";
50 | ```
51 | ctrl + s to save
52 |
53 | 7- Run your NextJS Project
54 |
55 | ```shell
56 | npm run dev
57 | ```
58 |
59 | 8- TEST
60 |
61 | - Navigate to your project page and proceed to test by clicking "Connect Wallet"
62 |
63 | with the wallet that holds the NFTs. You should be redirected to a "Welcome" page.
64 |
65 | - Attempt the same test with another wallet that doesn't have NFTs and you should
66 |
67 | be redirected to an "Access Denied" page.
68 |
69 | - Switch back to the wallet that has NFTs and get to the "Welcome" page.
70 |
71 | - Switch to the wallet that doesn't have NFTs and you should be auto redirected
72 | to the "Access Denied" page.
73 |
74 |
75 | Follow the video tutorial for explanations and guidance!
76 |
--------------------------------------------------------------------------------
/Part1/components/config.js:
--------------------------------------------------------------------------------
1 |
2 | export const nftcontract = "REPLACE WITH NFT SMART CONTRACT ADDRESS";
3 |
--------------------------------------------------------------------------------
/Part1/components/nftabi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "anonymous": false,
4 | "inputs": [
5 | {
6 | "indexed": true,
7 | "internalType": "address",
8 | "name": "owner",
9 | "type": "address"
10 | },
11 | {
12 | "indexed": true,
13 | "internalType": "address",
14 | "name": "approved",
15 | "type": "address"
16 | },
17 | {
18 | "indexed": true,
19 | "internalType": "uint256",
20 | "name": "tokenId",
21 | "type": "uint256"
22 | }
23 | ],
24 | "name": "Approval",
25 | "type": "event"
26 | },
27 | {
28 | "anonymous": false,
29 | "inputs": [
30 | {
31 | "indexed": true,
32 | "internalType": "address",
33 | "name": "owner",
34 | "type": "address"
35 | },
36 | {
37 | "indexed": true,
38 | "internalType": "address",
39 | "name": "operator",
40 | "type": "address"
41 | },
42 | {
43 | "indexed": false,
44 | "internalType": "bool",
45 | "name": "approved",
46 | "type": "bool"
47 | }
48 | ],
49 | "name": "ApprovalForAll",
50 | "type": "event"
51 | },
52 | {
53 | "anonymous": false,
54 | "inputs": [
55 | {
56 | "indexed": true,
57 | "internalType": "address",
58 | "name": "previousOwner",
59 | "type": "address"
60 | },
61 | {
62 | "indexed": true,
63 | "internalType": "address",
64 | "name": "newOwner",
65 | "type": "address"
66 | }
67 | ],
68 | "name": "OwnershipTransferred",
69 | "type": "event"
70 | },
71 | {
72 | "anonymous": false,
73 | "inputs": [
74 | {
75 | "indexed": true,
76 | "internalType": "address",
77 | "name": "from",
78 | "type": "address"
79 | },
80 | {
81 | "indexed": true,
82 | "internalType": "address",
83 | "name": "to",
84 | "type": "address"
85 | },
86 | {
87 | "indexed": true,
88 | "internalType": "uint256",
89 | "name": "tokenId",
90 | "type": "uint256"
91 | }
92 | ],
93 | "name": "Transfer",
94 | "type": "event"
95 | },
96 | {
97 | "inputs": [
98 | {
99 | "internalType": "address",
100 | "name": "to",
101 | "type": "address"
102 | },
103 | {
104 | "internalType": "uint256",
105 | "name": "tokenId",
106 | "type": "uint256"
107 | }
108 | ],
109 | "name": "approve",
110 | "outputs": [],
111 | "stateMutability": "nonpayable",
112 | "type": "function"
113 | },
114 | {
115 | "inputs": [
116 | {
117 | "internalType": "address",
118 | "name": "_to",
119 | "type": "address"
120 | },
121 | {
122 | "internalType": "uint256",
123 | "name": "_mintAmount",
124 | "type": "uint256"
125 | }
126 | ],
127 | "name": "mint",
128 | "outputs": [],
129 | "stateMutability": "payable",
130 | "type": "function"
131 | },
132 | {
133 | "inputs": [
134 | {
135 | "internalType": "bool",
136 | "name": "_state",
137 | "type": "bool"
138 | }
139 | ],
140 | "name": "pause",
141 | "outputs": [],
142 | "stateMutability": "nonpayable",
143 | "type": "function"
144 | },
145 | {
146 | "inputs": [],
147 | "name": "renounceOwnership",
148 | "outputs": [],
149 | "stateMutability": "nonpayable",
150 | "type": "function"
151 | },
152 | {
153 | "inputs": [
154 | {
155 | "internalType": "address",
156 | "name": "from",
157 | "type": "address"
158 | },
159 | {
160 | "internalType": "address",
161 | "name": "to",
162 | "type": "address"
163 | },
164 | {
165 | "internalType": "uint256",
166 | "name": "tokenId",
167 | "type": "uint256"
168 | }
169 | ],
170 | "name": "safeTransferFrom",
171 | "outputs": [],
172 | "stateMutability": "nonpayable",
173 | "type": "function"
174 | },
175 | {
176 | "inputs": [
177 | {
178 | "internalType": "address",
179 | "name": "from",
180 | "type": "address"
181 | },
182 | {
183 | "internalType": "address",
184 | "name": "to",
185 | "type": "address"
186 | },
187 | {
188 | "internalType": "uint256",
189 | "name": "tokenId",
190 | "type": "uint256"
191 | },
192 | {
193 | "internalType": "bytes",
194 | "name": "data",
195 | "type": "bytes"
196 | }
197 | ],
198 | "name": "safeTransferFrom",
199 | "outputs": [],
200 | "stateMutability": "nonpayable",
201 | "type": "function"
202 | },
203 | {
204 | "inputs": [
205 | {
206 | "internalType": "address",
207 | "name": "operator",
208 | "type": "address"
209 | },
210 | {
211 | "internalType": "bool",
212 | "name": "approved",
213 | "type": "bool"
214 | }
215 | ],
216 | "name": "setApprovalForAll",
217 | "outputs": [],
218 | "stateMutability": "nonpayable",
219 | "type": "function"
220 | },
221 | {
222 | "inputs": [
223 | {
224 | "internalType": "string",
225 | "name": "_newBaseExtension",
226 | "type": "string"
227 | }
228 | ],
229 | "name": "setBaseExtension",
230 | "outputs": [],
231 | "stateMutability": "nonpayable",
232 | "type": "function"
233 | },
234 | {
235 | "inputs": [
236 | {
237 | "internalType": "string",
238 | "name": "_newBaseURI",
239 | "type": "string"
240 | }
241 | ],
242 | "name": "setBaseURI",
243 | "outputs": [],
244 | "stateMutability": "nonpayable",
245 | "type": "function"
246 | },
247 | {
248 | "inputs": [
249 | {
250 | "internalType": "uint256",
251 | "name": "_newmaxMintAmount",
252 | "type": "uint256"
253 | }
254 | ],
255 | "name": "setmaxMintAmount",
256 | "outputs": [],
257 | "stateMutability": "nonpayable",
258 | "type": "function"
259 | },
260 | {
261 | "inputs": [
262 | {
263 | "internalType": "address",
264 | "name": "from",
265 | "type": "address"
266 | },
267 | {
268 | "internalType": "address",
269 | "name": "to",
270 | "type": "address"
271 | },
272 | {
273 | "internalType": "uint256",
274 | "name": "tokenId",
275 | "type": "uint256"
276 | }
277 | ],
278 | "name": "transferFrom",
279 | "outputs": [],
280 | "stateMutability": "nonpayable",
281 | "type": "function"
282 | },
283 | {
284 | "inputs": [
285 | {
286 | "internalType": "address",
287 | "name": "newOwner",
288 | "type": "address"
289 | }
290 | ],
291 | "name": "transferOwnership",
292 | "outputs": [],
293 | "stateMutability": "nonpayable",
294 | "type": "function"
295 | },
296 | {
297 | "inputs": [],
298 | "name": "withdraw",
299 | "outputs": [],
300 | "stateMutability": "payable",
301 | "type": "function"
302 | },
303 | {
304 | "inputs": [],
305 | "stateMutability": "nonpayable",
306 | "type": "constructor"
307 | },
308 | {
309 | "inputs": [
310 | {
311 | "internalType": "address",
312 | "name": "owner",
313 | "type": "address"
314 | }
315 | ],
316 | "name": "balanceOf",
317 | "outputs": [
318 | {
319 | "internalType": "uint256",
320 | "name": "",
321 | "type": "uint256"
322 | }
323 | ],
324 | "stateMutability": "view",
325 | "type": "function"
326 | },
327 | {
328 | "inputs": [],
329 | "name": "baseExtension",
330 | "outputs": [
331 | {
332 | "internalType": "string",
333 | "name": "",
334 | "type": "string"
335 | }
336 | ],
337 | "stateMutability": "view",
338 | "type": "function"
339 | },
340 | {
341 | "inputs": [],
342 | "name": "baseURI",
343 | "outputs": [
344 | {
345 | "internalType": "string",
346 | "name": "",
347 | "type": "string"
348 | }
349 | ],
350 | "stateMutability": "view",
351 | "type": "function"
352 | },
353 | {
354 | "inputs": [
355 | {
356 | "internalType": "uint256",
357 | "name": "tokenId",
358 | "type": "uint256"
359 | }
360 | ],
361 | "name": "getApproved",
362 | "outputs": [
363 | {
364 | "internalType": "address",
365 | "name": "",
366 | "type": "address"
367 | }
368 | ],
369 | "stateMutability": "view",
370 | "type": "function"
371 | },
372 | {
373 | "inputs": [
374 | {
375 | "internalType": "address",
376 | "name": "owner",
377 | "type": "address"
378 | },
379 | {
380 | "internalType": "address",
381 | "name": "operator",
382 | "type": "address"
383 | }
384 | ],
385 | "name": "isApprovedForAll",
386 | "outputs": [
387 | {
388 | "internalType": "bool",
389 | "name": "",
390 | "type": "bool"
391 | }
392 | ],
393 | "stateMutability": "view",
394 | "type": "function"
395 | },
396 | {
397 | "inputs": [],
398 | "name": "maxMintAmount",
399 | "outputs": [
400 | {
401 | "internalType": "uint256",
402 | "name": "",
403 | "type": "uint256"
404 | }
405 | ],
406 | "stateMutability": "view",
407 | "type": "function"
408 | },
409 | {
410 | "inputs": [],
411 | "name": "maxSupply",
412 | "outputs": [
413 | {
414 | "internalType": "uint256",
415 | "name": "",
416 | "type": "uint256"
417 | }
418 | ],
419 | "stateMutability": "view",
420 | "type": "function"
421 | },
422 | {
423 | "inputs": [],
424 | "name": "name",
425 | "outputs": [
426 | {
427 | "internalType": "string",
428 | "name": "",
429 | "type": "string"
430 | }
431 | ],
432 | "stateMutability": "view",
433 | "type": "function"
434 | },
435 | {
436 | "inputs": [],
437 | "name": "owner",
438 | "outputs": [
439 | {
440 | "internalType": "address",
441 | "name": "",
442 | "type": "address"
443 | }
444 | ],
445 | "stateMutability": "view",
446 | "type": "function"
447 | },
448 | {
449 | "inputs": [
450 | {
451 | "internalType": "uint256",
452 | "name": "tokenId",
453 | "type": "uint256"
454 | }
455 | ],
456 | "name": "ownerOf",
457 | "outputs": [
458 | {
459 | "internalType": "address",
460 | "name": "",
461 | "type": "address"
462 | }
463 | ],
464 | "stateMutability": "view",
465 | "type": "function"
466 | },
467 | {
468 | "inputs": [],
469 | "name": "paused",
470 | "outputs": [
471 | {
472 | "internalType": "bool",
473 | "name": "",
474 | "type": "bool"
475 | }
476 | ],
477 | "stateMutability": "view",
478 | "type": "function"
479 | },
480 | {
481 | "inputs": [
482 | {
483 | "internalType": "bytes4",
484 | "name": "interfaceId",
485 | "type": "bytes4"
486 | }
487 | ],
488 | "name": "supportsInterface",
489 | "outputs": [
490 | {
491 | "internalType": "bool",
492 | "name": "",
493 | "type": "bool"
494 | }
495 | ],
496 | "stateMutability": "view",
497 | "type": "function"
498 | },
499 | {
500 | "inputs": [],
501 | "name": "symbol",
502 | "outputs": [
503 | {
504 | "internalType": "string",
505 | "name": "",
506 | "type": "string"
507 | }
508 | ],
509 | "stateMutability": "view",
510 | "type": "function"
511 | },
512 | {
513 | "inputs": [
514 | {
515 | "internalType": "uint256",
516 | "name": "index",
517 | "type": "uint256"
518 | }
519 | ],
520 | "name": "tokenByIndex",
521 | "outputs": [
522 | {
523 | "internalType": "uint256",
524 | "name": "",
525 | "type": "uint256"
526 | }
527 | ],
528 | "stateMutability": "view",
529 | "type": "function"
530 | },
531 | {
532 | "inputs": [
533 | {
534 | "internalType": "address",
535 | "name": "owner",
536 | "type": "address"
537 | },
538 | {
539 | "internalType": "uint256",
540 | "name": "index",
541 | "type": "uint256"
542 | }
543 | ],
544 | "name": "tokenOfOwnerByIndex",
545 | "outputs": [
546 | {
547 | "internalType": "uint256",
548 | "name": "",
549 | "type": "uint256"
550 | }
551 | ],
552 | "stateMutability": "view",
553 | "type": "function"
554 | },
555 | {
556 | "inputs": [
557 | {
558 | "internalType": "uint256",
559 | "name": "tokenId",
560 | "type": "uint256"
561 | }
562 | ],
563 | "name": "tokenURI",
564 | "outputs": [
565 | {
566 | "internalType": "string",
567 | "name": "",
568 | "type": "string"
569 | }
570 | ],
571 | "stateMutability": "view",
572 | "type": "function"
573 | },
574 | {
575 | "inputs": [],
576 | "name": "totalSupply",
577 | "outputs": [
578 | {
579 | "internalType": "uint256",
580 | "name": "",
581 | "type": "uint256"
582 | }
583 | ],
584 | "stateMutability": "view",
585 | "type": "function"
586 | },
587 | {
588 | "inputs": [
589 | {
590 | "internalType": "address",
591 | "name": "_owner",
592 | "type": "address"
593 | }
594 | ],
595 | "name": "walletOfOwner",
596 | "outputs": [
597 | {
598 | "internalType": "uint256[]",
599 | "name": "",
600 | "type": "uint256[]"
601 | }
602 | ],
603 | "stateMutability": "view",
604 | "type": "function"
605 | }
606 | ]
--------------------------------------------------------------------------------
/Part1/components/web3connect.js:
--------------------------------------------------------------------------------
1 | import { nftcontract } from "./config";
2 | import NFTABI from './nftabi.json';
3 | import { ethers } from "ethers";
4 | import Web3Modal from 'web3modal';
5 |
6 | export async function connectWallet() {
7 | const web3Modal = new Web3Modal();
8 | const connection = await web3Modal.connect()
9 | const provider = new ethers.providers.Web3Provider(connection)
10 | const signer = provider.getSigner()
11 | const addressraw = signer.getAddress()
12 | const addressstr = (await addressraw).valueOf()
13 | let contract = new ethers.Contract(nftcontract, NFTABI, signer);
14 | let getids = await contract.walletOfOwner(addressstr);
15 | if (getids[0] === undefined){
16 | return 0;
17 | }
18 | else {
19 | return 1;
20 | }
21 | }
--------------------------------------------------------------------------------
/Part1/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../styles/globals.css'
2 |
3 | function MyApp({ Component, pageProps }) {
4 | return
5 | }
6 |
7 | export default MyApp
8 |
--------------------------------------------------------------------------------
/Part1/pages/api/hello.js:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 |
3 | export default function handler(req, res) {
4 | res.status(200).json({ name: 'John Doe' })
5 | }
6 |
--------------------------------------------------------------------------------
/Part1/pages/denied.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import Image from 'next/image'
3 | import styles from '../styles/Home.module.css'
4 | import { connectWallet } from '../components/web3connect';
5 | import { useRouter } from 'next/router';
6 | import { useEffect } from 'react';
7 |
8 | export default function Home() {
9 | const router = useRouter();
10 |
11 | async function verifyUser() {
12 | const output = await connectWallet();
13 | // console.log(output);
14 | if (output === 0) {
15 | router.push("/denied");
16 | } else {
17 | router.push("/welcome");
18 | }
19 | }
20 |
21 | useEffect(() => {
22 | const checkAuth = setInterval(() => {
23 | verifyUser();
24 | }, 2000);
25 | return () => clearInterval(checkAuth);
26 | }, []);
27 |
28 | return (
29 |
30 |
31 |
Create Next App
32 |
33 |
34 |
35 |
36 |
37 |
38 | ACCESS DENIED
39 |
40 |
41 |
42 | )
43 | }
44 |
--------------------------------------------------------------------------------
/Part1/pages/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import Image from 'next/image'
3 | import styles from '../styles/Home.module.css'
4 | import { connectWallet } from '../components/web3connect'
5 | import { useRouter } from 'next/router';
6 |
7 |
8 | export default function Home() {
9 |
10 | const router = useRouter();
11 |
12 | async function verifyUser() {
13 | const output = await connectWallet()
14 | if (output === 0) {
15 | router.push('/denied')
16 | }
17 | else {
18 | router.push('/welcome')
19 | }
20 | }
21 |
22 | return (
23 |
24 |
25 |
Create Next App
26 |
27 |
28 |
29 |
30 |
31 |
32 | Connect to App CONNECT WALLET
33 |
34 |
35 |
36 | Get started by editing{' '}
37 | pages/index.js
38 |
39 |
40 |
69 |
70 |
71 |
83 |
84 | )
85 | }
86 |
--------------------------------------------------------------------------------
/Part1/pages/welcome.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import Image from 'next/image'
3 | import styles from '../styles/Home.module.css';
4 | import { connectWallet } from '../components/web3connect';
5 | import { useRouter } from 'next/router';
6 | import { useEffect } from 'react';
7 |
8 | export default function Home() {
9 |
10 | const router = useRouter()
11 |
12 | useEffect(() => {
13 | const checkauth = setInterval(() => {
14 | verifyUser()
15 | }, 2000)
16 | return () => clearInterval(checkauth)
17 | })
18 |
19 | async function verifyUser() {
20 | const output = await connectWallet()
21 | if (output === 0) {
22 | router.push('/denied')
23 | }
24 | else {
25 | router.push('/welcome')
26 | }
27 | }
28 |
29 |
30 | return (
31 |
32 |
33 |
Create Next App
34 |
35 |
36 |
37 |
38 |
39 |
40 | Welcome!
41 |
42 |
43 |
44 | )
45 | }
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Web3-NFT-User-Authentication
2 | ⚡ A very straightfoward guide to authenticate users in NextJS with NFTs. Block users that aren't holding a specific ERC721 NFT
3 |
4 |
5 | Part 1: Securing Apps with NFTs
6 | Refer to "Part 1" folder attached.
7 |
--------------------------------------------------------------------------------