├── .env.example ├── .eslintrc.json ├── .gitignore ├── CHANGELOG.md ├── README.md ├── docker-compose.yml ├── next.config.mjs ├── package.json ├── prisma ├── migrations │ ├── 20240829155609_init │ │ └── migration.sql │ ├── 20240829161751_ │ │ └── migration.sql │ ├── 20240830061537_init │ │ └── migration.sql │ └── migration_lock.toml └── schema │ ├── account.prisma │ ├── schema.prisma │ ├── session.prisma │ └── user.prisma ├── public ├── example.png ├── example1.png ├── example2.png ├── example3.png ├── github-intro.png ├── ic-facebook.png ├── ic-github.png ├── ic-google.png ├── ic-line.png ├── logo.png ├── next.svg ├── og-image.png └── vercel.svg ├── src ├── app │ ├── api │ │ ├── auth │ │ │ └── [...nextauth] │ │ │ │ └── route.ts │ │ ├── register │ │ │ └── route.ts │ │ ├── users │ │ │ ├── avatar │ │ │ │ └── route.ts │ │ │ ├── resetPassword │ │ │ │ └── route.ts │ │ │ ├── route.ts │ │ │ └── sendResetPasswordEmail │ │ │ │ └── route.ts │ │ └── verify │ │ │ └── route.ts │ ├── favicon.ico │ ├── forgotPassword │ │ └── page.tsx │ ├── globals.css │ ├── layout.tsx │ ├── page.tsx │ ├── register │ │ └── page.tsx │ ├── repository │ │ ├── user.ts │ │ └── verification.ts │ ├── resetPassword │ │ └── page.tsx │ ├── service │ │ ├── email │ │ │ ├── index.ts │ │ │ ├── resetPassword.ts │ │ │ ├── verify.ts │ │ │ └── welcome.ts │ │ ├── resetPassword │ │ │ └── index.ts │ │ └── verification │ │ │ └── index.ts │ ├── signin │ │ └── page.tsx │ └── verification │ │ ├── Verify.tsx │ │ └── page.tsx ├── auth.ts ├── components │ ├── client │ │ ├── Button │ │ │ └── index.tsx │ │ ├── FacebookSigninButton.tsx │ │ ├── GithubSigninButton.tsx │ │ ├── GoogleSigninButton.tsx │ │ ├── LineSigninButton.tsx │ │ ├── RegisterForm.tsx │ │ ├── ResetPasswordForm.tsx │ │ ├── SendForgotPasswordLinkForm.tsx │ │ ├── SigninForm.tsx │ │ ├── SignoutButton.tsx │ │ ├── TextField │ │ │ └── index.tsx │ │ ├── Title.tsx │ │ ├── UploadAvatarDialog.tsx │ │ ├── UserAvatar.tsx │ │ └── UserList.tsx │ └── email │ │ ├── ResetPassword.tsx │ │ ├── SigninWelcome.tsx │ │ └── Verify.tsx ├── hooks │ └── useDisclosure.ts ├── providers │ ├── Provider.tsx │ └── constants.tsx └── theme.ts ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | # GOOGLE SIGNIN 2 | AUTH_GOOGLE_ID= 3 | AUTH_GOOGLE_SECRET= 4 | 5 | # GITHUB SIGNIN 6 | AUTH_GITHUB_ID= 7 | AUTH_GITHUB_SECRET= 8 | 9 | # FACEBOOK SIGNIN 10 | AUTH_FACEBOOK_ID= 11 | AUTH_FACEBOOK_SECRET= 12 | 13 | #LINE SIGNIN 14 | AUTH_LINE_ID= 15 | AUTH_LINE_SECRET= 16 | 17 | # JWT 18 | JWT_SECRET= 19 | 20 | # DB 21 | DB_USER=postgres 22 | DB_PASSWORD=postgres 23 | POSTGRES_URL=postgresql://postgres:postgres@localhost:5432/postgres?schema=public 24 | 25 | # API URL 26 | NEXT_PUBLIC_API_URL=http://localhost:3000/api 27 | 28 | # Web URL 29 | URL=http://localhost:3000 30 | 31 | # Email API Key 32 | RESEND_API_KEY= 33 | 34 | # Vercel Blob Token 35 | BLOB_READ_WRITE_TOKEN= 36 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## [0.4.0](https://github.com/Dannyisadog/nextjs-authjs-template/compare/v0.2.0...v0.4.0) (2024-09-02) 6 | 7 | 8 | ### Features 9 | 10 | * **api:** add update user avatar api ([a2a1113](https://github.com/Dannyisadog/nextjs-authjs-template/commit/a2a1113c2aeb303b56f0ca5d98c2d62f62dd6e82)) 11 | * **api:** add verify email ([5573a84](https://github.com/Dannyisadog/nextjs-authjs-template/commit/5573a84962420e46aaa1f4af22b3607a9d1c3bac)) 12 | * **api:** send welcome email when register successfully ([ae76da1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ae76da120549b4efe7a713e032706f6a31242e1f)) 13 | * **app:** adjust layout metadata ([e852828](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e8528287fc19be28434d0b2e2cd932ab041206f6)) 14 | * **auth:** add prisma adapter ([705adc9](https://github.com/Dannyisadog/nextjs-authjs-template/commit/705adc9e05bd569c92b9e0c67f194334f510f2ef)) 15 | * **auth:** adjust session type ([ae20616](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ae20616a86d37f3f16cf23f7c7ff430a508e9776)) 16 | * **component:** add upload avatar dialog ([872ab3e](https://github.com/Dannyisadog/nextjs-authjs-template/commit/872ab3ea9effb8c5d551635f64a582b6810d2864)) 17 | * **component:** add upload user avatar dialog in user avatar ([da79164](https://github.com/Dannyisadog/nextjs-authjs-template/commit/da79164237dfb95a6196b24514f58681ec51de47)) 18 | * **component:** get users from provider ([76e9361](https://github.com/Dannyisadog/nextjs-authjs-template/commit/76e93618e8644f571fb40811a39e04a62b6db8e2)) 19 | * **email:** add email verification template ([e9aa759](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e9aa759c6f4e2e13ce86b807d9c58e58d4bd75b7)) 20 | * **email:** send email verification when register & first login ([b5201c5](https://github.com/Dannyisadog/nextjs-authjs-template/commit/b5201c5675a188aa1e2c81f0cbb9955da5f23790)) 21 | * **hook:** add useDisclosure hook ([3d373e9](https://github.com/Dannyisadog/nextjs-authjs-template/commit/3d373e9d4e155656f6f96a794c80715945298933)) 22 | * **middleware:** remove middleware for auth.js bug ([276c1f1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/276c1f15c016dca7dd5badb871d49aca00b211bd)) 23 | * **package:** add jwt package ([e2f4631](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e2f4631b8a47ef9632131d6ccc93ae04f316538c)) 24 | * **package:** add prisma adapter package ([dcb91ab](https://github.com/Dannyisadog/nextjs-authjs-template/commit/dcb91abadd4fd6e41dd00c2a5de1ac3e41356e3a)) 25 | * **package:** update prisma & add vercel/blob package ([0f06435](https://github.com/Dannyisadog/nextjs-authjs-template/commit/0f064359acfa035d890586426c60a4f131a3b4e3)) 26 | * **page:** add verification page ([9d44dc7](https://github.com/Dannyisadog/nextjs-authjs-template/commit/9d44dc77304284d56a2d9a2a1b147cf9c5c6a5c2)) 27 | * **page:** display error message when verify failed ([7027a43](https://github.com/Dannyisadog/nextjs-authjs-template/commit/7027a43f56e377e938bb62466a68d35ca6dd39b7)) 28 | * **page:** display user verification status ([6885888](https://github.com/Dannyisadog/nextjs-authjs-template/commit/688588801cd143e808901012e288730ea55ef7d6)) 29 | * **prisma:** add & update schemas and migrations ([abeda08](https://github.com/Dannyisadog/nextjs-authjs-template/commit/abeda081232e6cd332d41f00e5c7ef918e09a1de)) 30 | * **provider:** add global provider ([68da421](https://github.com/Dannyisadog/nextjs-authjs-template/commit/68da4210c995e5976788a6f829bb52c74c6250fd)) 31 | * **repository:** add update function in user repository ([0f538f1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/0f538f1ca1da12b8d694256e391d791dcc86d349)) 32 | * **repository:** add verification repository ([cfd624a](https://github.com/Dannyisadog/nextjs-authjs-template/commit/cfd624a09d0d71fb276c3e9ed7f41f218d81fcae)) 33 | * **repository:** adjust user update for emailVerified ([5776a95](https://github.com/Dannyisadog/nextjs-authjs-template/commit/5776a95221a09494f71b27dabb5e10b06d2a2fca)) 34 | * **service:** add base email service ([ac7663c](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ac7663cd42d03b0779cf0eb89354308eb862eb90)) 35 | * **service:** add send welcome email service ([be26376](https://github.com/Dannyisadog/nextjs-authjs-template/commit/be26376cf3882c64d4fcce63bc563441e85bb674)) 36 | * **service:** add service to send verification email ([e5052e4](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e5052e47d9322bf9bebc9e42187f9d10ed346878)) 37 | * **service:** add verification service ([ebe99c2](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ebe99c22a7ea4067bd177da392936baac5783e94)) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * **api:** return error response when exception happened ([2f8a614](https://github.com/Dannyisadog/nextjs-authjs-template/commit/2f8a614b8b8b1fd5759dd12479778bcce0e542b1)) 43 | * **repository:** remove condition to check user exist ([0aa67c0](https://github.com/Dannyisadog/nextjs-authjs-template/commit/0aa67c05636a888ad1fc7f2d2985104f1a8904c0)) 44 | * **service:** throw error when verify token failed ([cf1b1e7](https://github.com/Dannyisadog/nextjs-authjs-template/commit/cf1b1e7672a0c042c292b8d0e248b16420d62c10)) 45 | 46 | ## [0.3.0](https://github.com/Dannyisadog/nextjs-authjs-template/compare/v0.2.0...v0.3.0) (2024-08-30) 47 | 48 | 49 | ### Features 50 | 51 | * **api:** add update user avatar api ([a2a1113](https://github.com/Dannyisadog/nextjs-authjs-template/commit/a2a1113c2aeb303b56f0ca5d98c2d62f62dd6e82)) 52 | * **auth:** add prisma adapter ([705adc9](https://github.com/Dannyisadog/nextjs-authjs-template/commit/705adc9e05bd569c92b9e0c67f194334f510f2ef)) 53 | * **component:** add upload avatar dialog ([872ab3e](https://github.com/Dannyisadog/nextjs-authjs-template/commit/872ab3ea9effb8c5d551635f64a582b6810d2864)) 54 | * **component:** add upload user avatar dialog in user avatar ([da79164](https://github.com/Dannyisadog/nextjs-authjs-template/commit/da79164237dfb95a6196b24514f58681ec51de47)) 55 | * **component:** get users from provider ([76e9361](https://github.com/Dannyisadog/nextjs-authjs-template/commit/76e93618e8644f571fb40811a39e04a62b6db8e2)) 56 | * **hook:** add useDisclosure hook ([3d373e9](https://github.com/Dannyisadog/nextjs-authjs-template/commit/3d373e9d4e155656f6f96a794c80715945298933)) 57 | * **middleware:** remove middleware for auth.js bug ([276c1f1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/276c1f15c016dca7dd5badb871d49aca00b211bd)) 58 | * **package:** add prisma adapter package ([dcb91ab](https://github.com/Dannyisadog/nextjs-authjs-template/commit/dcb91abadd4fd6e41dd00c2a5de1ac3e41356e3a)) 59 | * **package:** update prisma & add vercel/blob package ([0f06435](https://github.com/Dannyisadog/nextjs-authjs-template/commit/0f064359acfa035d890586426c60a4f131a3b4e3)) 60 | * **prisma:** add & update schemas and migrations ([abeda08](https://github.com/Dannyisadog/nextjs-authjs-template/commit/abeda081232e6cd332d41f00e5c7ef918e09a1de)) 61 | * **provider:** add global provider ([68da421](https://github.com/Dannyisadog/nextjs-authjs-template/commit/68da4210c995e5976788a6f829bb52c74c6250fd)) 62 | * **repository:** add update function in user repository ([0f538f1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/0f538f1ca1da12b8d694256e391d791dcc86d349)) 63 | 64 | ## 0.1.0 (2024-08-28) 65 | 66 | 67 | ### Features 68 | 69 | * **api:** add register api ([5a9ce72](https://github.com/Dannyisadog/nextjs-authjs-template/commit/5a9ce723e8248c345a501daab5e776755f0338bb)) 70 | * **api:** add users crud api ([36a0a56](https://github.com/Dannyisadog/nextjs-authjs-template/commit/36a0a5680a4a06f266ecb177398c01ae3a91fcab)) 71 | * **api:** protect get users api ([0a05164](https://github.com/Dannyisadog/nextjs-authjs-template/commit/0a05164db84cd63f9b92bc12089e1f0a1cdf8d7b)) 72 | * **api:** remove create user api ([ec83269](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ec8326981827ac2dd67fd328d3bd02a59ce6c46e)) 73 | * **app:** add og title & image ([a280fa6](https://github.com/Dannyisadog/nextjs-authjs-template/commit/a280fa6c46e3765520926bc029281c266a96c10b)) 74 | * **auth:** add credential signin ([59240e1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/59240e119230e607afcb84f770be6e39dcd24a43)) 75 | * **auth:** add Github provider in auth providers ([9ee1c58](https://github.com/Dannyisadog/nextjs-authjs-template/commit/9ee1c5802f874fc422131b5e4a2f15713addc3da)) 76 | * **auth:** add image when first signin create user ([fcece58](https://github.com/Dannyisadog/nextjs-authjs-template/commit/fcece587591d62a8d17e774f492c9d09e4d912d0)) 77 | * **auth:** send welcome email when first signin ([fbc945b](https://github.com/Dannyisadog/nextjs-authjs-template/commit/fbc945bfe27e1c8e9c59165abc1604fde24a579a)) 78 | * **component:** add button loading & disable status ([d782632](https://github.com/Dannyisadog/nextjs-authjs-template/commit/d782632dcba6750f18b73821a4c5a27d16d11721)) 79 | * **component:** add common button component ([fbe1ead](https://github.com/Dannyisadog/nextjs-authjs-template/commit/fbe1ead59e346a656fc483d50ac49696ce848483)) 80 | * **component:** add common textfield component ([8093a21](https://github.com/Dannyisadog/nextjs-authjs-template/commit/8093a21ac7fb65d8ba6fffef8d1ab7df86214c9b)) 81 | * **component:** add github link title component ([63b0e59](https://github.com/Dannyisadog/nextjs-authjs-template/commit/63b0e598024c4e392ccdd0523aa25be30b9b03ef)) 82 | * **component:** add github signin button ([cb9f118](https://github.com/Dannyisadog/nextjs-authjs-template/commit/cb9f118141ec6948120ef8fbc9720f53914b070e)) 83 | * **component:** add goBack option in title component ([72e4818](https://github.com/Dannyisadog/nextjs-authjs-template/commit/72e48184d7f9d99f0ef3d6ea0d0cffad289938ce)) 84 | * **component:** add google signin button component ([835ff5b](https://github.com/Dannyisadog/nextjs-authjs-template/commit/835ff5be8247faaef5ae9936a29613791ee8ac5d)) 85 | * **component:** add loading status in google signin & signout button ([232068a](https://github.com/Dannyisadog/nextjs-authjs-template/commit/232068a92085dd1e875377cd148463c682bd0845)) 86 | * **component:** add register link in signin form ([bfcd943](https://github.com/Dannyisadog/nextjs-authjs-template/commit/bfcd9431d322d5cb250333f5d772b658e2ad677c)) 87 | * **component:** add signin button status ([d002649](https://github.com/Dannyisadog/nextjs-authjs-template/commit/d002649ee09910a3ce3bed33c04556bdc7b2482e)) 88 | * **component:** add signin form component ([82c38cb](https://github.com/Dannyisadog/nextjs-authjs-template/commit/82c38cbc6a2459b078ee17261586e6c33536de12)) 89 | * **component:** add signin welcome email template ([8421a05](https://github.com/Dannyisadog/nextjs-authjs-template/commit/8421a05ea9349f9c7605d519b29b74fdebdface0)) 90 | * **component:** add title component ([2a2bbe6](https://github.com/Dannyisadog/nextjs-authjs-template/commit/2a2bbe6b4be74e289c1188640e81f4248dcbac33)) 91 | * **component:** add user list ([da8ce21](https://github.com/Dannyisadog/nextjs-authjs-template/commit/da8ce2105408b1d03b5965d21309395c7005c3a2)) 92 | * **component:** adjust components style ([835bf72](https://github.com/Dannyisadog/nextjs-authjs-template/commit/835bf72ecbdc81b80575138fad75df54db382def)) 93 | * **component:** adjust error message style ([dabda98](https://github.com/Dannyisadog/nextjs-authjs-template/commit/dabda98dab169867e41cfdfdc1f8f8e11ee3f924)) 94 | * **component:** adjust title height ([5d9cc0e](https://github.com/Dannyisadog/nextjs-authjs-template/commit/5d9cc0ee53a9c556f56d0950bdf9a87a08ee2993)) 95 | * **component:** display github icon conditionally ([2c797d5](https://github.com/Dannyisadog/nextjs-authjs-template/commit/2c797d5965360984a9cf76eb9cfddde4ee0f13bc)) 96 | * **component:** display user list ([22868c6](https://github.com/Dannyisadog/nextjs-authjs-template/commit/22868c6be99d0bfb76f4724c9bdd21fe659ad0f2)) 97 | * **component:** move user list to client component ([543530c](https://github.com/Dannyisadog/nextjs-authjs-template/commit/543530ca26b3d1ed57d0c621c2d08c61661059b1)) 98 | * **component:** restyle error message ([833a8b4](https://github.com/Dannyisadog/nextjs-authjs-template/commit/833a8b4e8e8676fba7cc70d79279c70ac2cdabac)) 99 | * **component:** set register link color to primary ([57ce0ce](https://github.com/Dannyisadog/nextjs-authjs-template/commit/57ce0ce622afb75bec4d88ce977d30cc082670ea)) 100 | * **component:** validate signin form data in frontend ([e36e044](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e36e044bed7994c724689a362e9781876d740a49)) 101 | * **docker:** add docker-compose for postgres db ([3fb2f1f](https://github.com/Dannyisadog/nextjs-authjs-template/commit/3fb2f1fb9d83a4cf4b68a51bf5614f7ae1aa3616)) 102 | * **env:** add resend api key in env example ([1d83342](https://github.com/Dannyisadog/nextjs-authjs-template/commit/1d833428c172afa217aeda2c407ae071746d1a7a)) 103 | * **env:** update env example for github signin ([b2c7771](https://github.com/Dannyisadog/nextjs-authjs-template/commit/b2c7771cf5401c08bdf200b22da5a1b25b5dbcfe)) 104 | * **favicon:** update favicon ([39c5f53](https://github.com/Dannyisadog/nextjs-authjs-template/commit/39c5f53fdf019c344f34966b2df528e448d23ea5)) 105 | * **head:** adjust title & description ([f0290ff](https://github.com/Dannyisadog/nextjs-authjs-template/commit/f0290ff4ae11edaf7e315176f0ca1e0b2953dd1e)) 106 | * **layout:** add basic layout ([9f12ae1](https://github.com/Dannyisadog/nextjs-authjs-template/commit/9f12ae11913633cd07656f00f35c3505e2f08775)) 107 | * **layout:** add mui theme ([7eb6d8e](https://github.com/Dannyisadog/nextjs-authjs-template/commit/7eb6d8e8d7c3249b522777840641deb24de5d321)) 108 | * **layout:** adjust layout padding top ([475b653](https://github.com/Dannyisadog/nextjs-authjs-template/commit/475b653a85b64d130d9e53998f281fd5e2404148)) 109 | * **layout:** adjust layout padding y ([ddc1275](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ddc1275cb45cafc6c6c1f3fbac1efb8f6a8c4e7b)) 110 | * **layout:** inject vercel analytics into app layout ([4bc64a8](https://github.com/Dannyisadog/nextjs-authjs-template/commit/4bc64a8417dc4076501ac01105a48d46d9dbf863)) 111 | * **layout:** inject vercel speed insights into app layout ([cea4b7c](https://github.com/Dannyisadog/nextjs-authjs-template/commit/cea4b7c038aa4c96e085eae20ec04b2549b29cb5)) 112 | * **layout:** move viewport into head section ([1d1d1f2](https://github.com/Dannyisadog/nextjs-authjs-template/commit/1d1d1f218e43c43c27dceffdd06d12e740ab68ab)) 113 | * **meta:** adjust meta data ([8ed876d](https://github.com/Dannyisadog/nextjs-authjs-template/commit/8ed876d4840aafb2231121b51d2d7dde037f987e)) 114 | * **package:** add bcrypt & prisma package ([c5cb695](https://github.com/Dannyisadog/nextjs-authjs-template/commit/c5cb695766e720c3a31e7b3ffe75b6a690b10771)) 115 | * **package:** add mui icon package ([10e4f33](https://github.com/Dannyisadog/nextjs-authjs-template/commit/10e4f3300f8fb2714e04ae9502e6dda6ed269ca8)) 116 | * **package:** add resend & react-email packages ([67ee4b6](https://github.com/Dannyisadog/nextjs-authjs-template/commit/67ee4b6fb80ffbaec2fd2e2872da28322a290029)) 117 | * **package:** add standard-version package ([4909ab2](https://github.com/Dannyisadog/nextjs-authjs-template/commit/4909ab2c7bdc7b4e9472405738f0a28afa8557f9)) 118 | * **package:** add vercel analytics package ([260bfe8](https://github.com/Dannyisadog/nextjs-authjs-template/commit/260bfe81769ab1f8adc915a6a26b3d861456ef4a)) 119 | * **package:** add vercel speed insights package ([6d6a141](https://github.com/Dannyisadog/nextjs-authjs-template/commit/6d6a141a1c211829e203f0cba827d6065eba4dbd)) 120 | * **package:** install mui related packages ([e00e0ac](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e00e0ac50dcc48f12792c3fad0526a0e893356ab)) 121 | * **package:** remove @react-email/components package ([4f4741e](https://github.com/Dannyisadog/nextjs-authjs-template/commit/4f4741e48b5874c375fbc2216db70ff1a947358f)) 122 | * **page:** add github signin button into signin page ([6127901](https://github.com/Dannyisadog/nextjs-authjs-template/commit/61279012d7b93091db72003d42b8dbb7cd945571)) 123 | * **page:** add register form ([aedb59a](https://github.com/Dannyisadog/nextjs-authjs-template/commit/aedb59a40253ce2f3d5136b692428180ad98449e)) 124 | * **page:** add signin page ([ba16c68](https://github.com/Dannyisadog/nextjs-authjs-template/commit/ba16c689a1ad03c35f3e4c55a6f8048f69fc53cd)) 125 | * **page:** adjust api base url ([a7014e2](https://github.com/Dannyisadog/nextjs-authjs-template/commit/a7014e2adbf06eed02ddacf0ce76eb2f7dd82825)) 126 | * **page:** adjust home page ([8743c63](https://github.com/Dannyisadog/nextjs-authjs-template/commit/8743c63591a4e7cdee43bc4ea97bdccb9d314035)) 127 | * **page:** adjust page style ([6a12a93](https://github.com/Dannyisadog/nextjs-authjs-template/commit/6a12a93c89e16beb072f4e42598de7438793c05b)) 128 | * **page:** adjust pages style ([dc5a1f8](https://github.com/Dannyisadog/nextjs-authjs-template/commit/dc5a1f808f71bb13dd50380f3eccc77779ff2562)) 129 | * **page:** remoe useless stuff ([3e2df11](https://github.com/Dannyisadog/nextjs-authjs-template/commit/3e2df117b49d655a2e894c5b4555341b1b034a8a)) 130 | * **prisma:** add prisma schema & model ([5cd84ed](https://github.com/Dannyisadog/nextjs-authjs-template/commit/5cd84ed10cce770f209c99517ddf9533925d416c)) 131 | * **prisma:** split user schema ([56049a7](https://github.com/Dannyisadog/nextjs-authjs-template/commit/56049a7d7fd9d46bf3af36e5229fe4bc49ed5bec)) 132 | * **repository:** add email param to get user ([8ee1ccc](https://github.com/Dannyisadog/nextjs-authjs-template/commit/8ee1cccec24a2d7f7a60a4821dc94d368606c567)) 133 | * **repository:** add image field when create user ([a1136d9](https://github.com/Dannyisadog/nextjs-authjs-template/commit/a1136d9bfa331c5761d5ce47f75c842925b695c1)) 134 | * **repository:** add user create with password ([8804b02](https://github.com/Dannyisadog/nextjs-authjs-template/commit/8804b02a9ed60b5232cad1dc7760a514de47ddc0)) 135 | * **repository:** add user repository ([b77b053](https://github.com/Dannyisadog/nextjs-authjs-template/commit/b77b0533faaad2fa81ac165d4bc9f8117a41eb8f)) 136 | * **repository:** adjust get user condition when deleted is false ([e89d494](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e89d49411981948e3ffb3e711b4c29bfc3b27972)) 137 | * **service:** add send email service ([e96c539](https://github.com/Dannyisadog/nextjs-authjs-template/commit/e96c53962e6de43846593a0b8e563c9ed8f46b1a)) 138 | * **style:** adjust global & page css ([3648605](https://github.com/Dannyisadog/nextjs-authjs-template/commit/364860556af90d8adbf561f89c83d9df15a44d51)) 139 | * **style:** remove page css ([1b84388](https://github.com/Dannyisadog/nextjs-authjs-template/commit/1b84388d929157068ce377b027757136d6fe1bfe)) 140 | * **style:** reset global css ([07befe8](https://github.com/Dannyisadog/nextjs-authjs-template/commit/07befe8bc59f61c212b1aa0a9b8bd07c03375467)) 141 | 142 | 143 | ### Bug Fixes 144 | 145 | * **component:** adjust email template using pure html tsx ([fab77ee](https://github.com/Dannyisadog/nextjs-authjs-template/commit/fab77ee1125bec54e8ee3de643dbd5055b97b131)) 146 | * **prisma:** split prisma schema ([b5ed7bb](https://github.com/Dannyisadog/nextjs-authjs-template/commit/b5ed7bb9dc061d635313eb07b2ccb972628bdad0)) 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Next.js Auth Template](https://nextauth.dannyisadog.com) 2 | 3 |  4 | 5 | The nextjs-authjs-template is a robust starter template for building modern web applications with Next.js and Auth.js (formerly NextAuth.js). This template is designed to streamline the development process by providing a pre-configured setup that integrates user authentication and authorization seamlessly into your Next.js project. 6 | 7 | ## Features: 8 | - FullStack [Next.js](https://nextjs.org/) application with built-in authentication. 9 | - User authentication with email, Google, and GitHub. 10 | - ORM with [Prisma](https://www.prisma.io/) for database management. 11 | - PostgreSQL database with Docker for easy setup. 12 | - Email service with [Resend](https://resend.com/) API. 13 | - [MUI](https://mui.com/) for styling and responsive design. 14 | 15 | 16 | ## Use Cases: 17 | - Rapidly prototype and deploy Next.js applications with built-in authentication. 18 | - Start new projects with a solid foundation, reducing the boilerplate code required for user management. 19 | 20 | ## Getting Started 21 | 22 | 1. Create a `.env` file in the root of the project and add the following 23 | 24 | ```bash 25 | cp .env.example .env 26 | ``` 27 | 28 | 2. Generate auth secret key 29 | 30 | ```bash 31 | npx auth secret 32 | ``` 33 | 34 | 3. Fill up your google & github client id & secret in `.env` 35 | 36 | ```bash 37 | ... 38 | AUTH_GOOGLE_ID=xxxx 39 | AUTH_GOOGLE_SECRET=xxxx 40 | 41 | AUTH_GITHUB_ID=xxxx 42 | AUTH_GITHUB_SECRET=xxxx 43 | ... 44 | ``` 45 | 46 | 4. Create your [Resend api key](https://resend.com/api-keys) for email service in `.env` 47 | 48 | ```bash 49 | ... 50 | RESEND_API_KEY=xxxx 51 | ... 52 | ``` 53 | 54 | 5. Install dependencies 55 | 56 | ```bash 57 | yarn install 58 | ``` 59 | 60 | 6. Start postgres database 61 | 62 | ```bash 63 | docker-compose up -d 64 | ``` 65 | 66 | 7. Run the development server: 67 | 68 | ```bash 69 | yarn dev 70 | ``` 71 | 72 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 73 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | postgres: 5 | container_name: postgres_db 6 | image: postgres 7 | environment: 8 | POSTGRES_USER: ${DB_USER} 9 | POSTGRES_PASSWORD: ${DB_PASSWORD} 10 | PGDATA: /data/postgres 11 | volumes: 12 | - postgres:/data/postgres 13 | ports: 14 | - "5432:5432" 15 | restart: unless-stopped 16 | 17 | volumes: 18 | postgres: 19 | -------------------------------------------------------------------------------- /next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: "https", 7 | hostname: "**", 8 | }, 9 | ], 10 | } 11 | }; 12 | 13 | export default nextConfig; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-authentication-template", 3 | "version": "0.4.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "postinstall": "prisma generate", 11 | "release": "standard-version" 12 | }, 13 | "dependencies": { 14 | "@auth/prisma-adapter": "^2.4.2", 15 | "@emotion/react": "^11.13.3", 16 | "@emotion/styled": "^11.13.0", 17 | "@mui/icons-material": "^5.16.7", 18 | "@mui/material": "^5.16.7", 19 | "@multiavatar/multiavatar": "^1.0.7", 20 | "@prisma/client": "^5.19.0", 21 | "@vercel/analytics": "^1.3.1", 22 | "@vercel/blob": "^0.23.4", 23 | "@vercel/speed-insights": "^1.0.12", 24 | "jsonwebtoken": "^9.0.2", 25 | "next": "14.2.5", 26 | "next-auth": "^5.0.0-beta.20", 27 | "react": "^18", 28 | "react-dom": "^18", 29 | "resend": "^4.0.0" 30 | }, 31 | "devDependencies": { 32 | "@types/bcryptjs": "^2.4.6", 33 | "@types/jsonwebtoken": "^9.0.6", 34 | "@types/node": "^20", 35 | "@types/react": "^18", 36 | "@types/react-dom": "^18", 37 | "bcryptjs": "^2.4.3", 38 | "eslint": "^8", 39 | "eslint-config-next": "14.2.5", 40 | "prisma": "^5.19.0", 41 | "standard-version": "^9.5.0", 42 | "typescript": "^5" 43 | } 44 | } -------------------------------------------------------------------------------- /prisma/migrations/20240829155609_init/migration.sql: -------------------------------------------------------------------------------- 1 | -- CreateTable 2 | CREATE TABLE "User" ( 3 | "id" SERIAL NOT NULL, 4 | "name" TEXT NOT NULL, 5 | "email" TEXT NOT NULL, 6 | "image" TEXT, 7 | "password" TEXT, 8 | "is_active" BOOLEAN NOT NULL DEFAULT false, 9 | "is_deleted" BOOLEAN NOT NULL DEFAULT false, 10 | "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 11 | "updated_at" TIMESTAMP(3), 12 | 13 | CONSTRAINT "User_pkey" PRIMARY KEY ("id") 14 | ); 15 | 16 | -- CreateIndex 17 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); 18 | -------------------------------------------------------------------------------- /prisma/migrations/20240829161751_/migration.sql: -------------------------------------------------------------------------------- 1 | -- AlterTable 2 | ALTER TABLE "User" ADD COLUMN "email_verified" TIMESTAMP(3); 3 | -------------------------------------------------------------------------------- /prisma/migrations/20240830061537_init/migration.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Warnings: 3 | 4 | - You are about to drop the column `email_verified` on the `User` table. All the data in the column will be lost. 5 | 6 | */ 7 | -- AlterTable 8 | ALTER TABLE "User" DROP COLUMN "email_verified", 9 | ADD COLUMN "emailVerified" TIMESTAMP(3); 10 | 11 | -- CreateTable 12 | CREATE TABLE "Account" ( 13 | "userId" INTEGER NOT NULL, 14 | "type" TEXT NOT NULL, 15 | "provider" TEXT NOT NULL, 16 | "providerAccountId" TEXT NOT NULL, 17 | "refresh_token" TEXT, 18 | "access_token" TEXT, 19 | "expires_at" INTEGER, 20 | "token_type" TEXT, 21 | "scope" TEXT, 22 | "id_token" TEXT, 23 | "session_state" TEXT, 24 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 25 | "updatedAt" TIMESTAMP(3) NOT NULL, 26 | 27 | CONSTRAINT "Account_pkey" PRIMARY KEY ("provider","providerAccountId") 28 | ); 29 | 30 | -- CreateTable 31 | CREATE TABLE "Session" ( 32 | "sessionToken" TEXT NOT NULL, 33 | "userId" INTEGER NOT NULL, 34 | "expires" TIMESTAMP(3) NOT NULL, 35 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, 36 | "updatedAt" TIMESTAMP(3) NOT NULL 37 | ); 38 | 39 | -- CreateIndex 40 | CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken"); 41 | 42 | -- AddForeignKey 43 | ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; 44 | 45 | -- AddForeignKey 46 | ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; 47 | -------------------------------------------------------------------------------- /prisma/migrations/migration_lock.toml: -------------------------------------------------------------------------------- 1 | # Please do not edit this file manually 2 | # It should be added in your version-control system (i.e. Git) 3 | provider = "postgresql" -------------------------------------------------------------------------------- /prisma/schema/account.prisma: -------------------------------------------------------------------------------- 1 | model Account { 2 | userId Int 3 | type String 4 | provider String 5 | providerAccountId String 6 | refresh_token String? 7 | access_token String? 8 | expires_at Int? 9 | token_type String? 10 | scope String? 11 | id_token String? 12 | session_state String? 13 | 14 | createdAt DateTime @default(now()) 15 | updatedAt DateTime @updatedAt 16 | 17 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 18 | 19 | @@id([provider, providerAccountId]) 20 | } 21 | -------------------------------------------------------------------------------- /prisma/schema/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? 5 | // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init 6 | 7 | generator client { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["prismaSchemaFolder"] 10 | } 11 | 12 | datasource db { 13 | provider = "postgresql" 14 | url = env("POSTGRES_URL") 15 | } 16 | -------------------------------------------------------------------------------- /prisma/schema/session.prisma: -------------------------------------------------------------------------------- 1 | model Session { 2 | sessionToken String @unique 3 | userId Int 4 | expires DateTime 5 | user User @relation(fields: [userId], references: [id], onDelete: Cascade) 6 | 7 | createdAt DateTime @default(now()) 8 | updatedAt DateTime @updatedAt 9 | } 10 | -------------------------------------------------------------------------------- /prisma/schema/user.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id @default(autoincrement()) 3 | name String 4 | email String @unique 5 | emailVerified DateTime? 6 | image String? 7 | password String? 8 | is_active Boolean @default(false) 9 | is_deleted Boolean @default(false) 10 | created_at DateTime @default(now()) 11 | updated_at DateTime? @updatedAt 12 | accounts Account[] 13 | sessions Session[] 14 | } 15 | -------------------------------------------------------------------------------- /public/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/example.png -------------------------------------------------------------------------------- /public/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/example1.png -------------------------------------------------------------------------------- /public/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/example2.png -------------------------------------------------------------------------------- /public/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/example3.png -------------------------------------------------------------------------------- /public/github-intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/github-intro.png -------------------------------------------------------------------------------- /public/ic-facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/ic-facebook.png -------------------------------------------------------------------------------- /public/ic-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/ic-github.png -------------------------------------------------------------------------------- /public/ic-google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/ic-google.png -------------------------------------------------------------------------------- /public/ic-line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/ic-line.png -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/logo.png -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/public/og-image.png -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import { handlers } from "auth" 2 | export const { GET, POST } = handlers -------------------------------------------------------------------------------- /src/app/api/register/route.ts: -------------------------------------------------------------------------------- 1 | import { create } from "app/repository/user"; 2 | import { sendVerificationEmail } from "app/service/email/verify"; 3 | import { sendWelcomeEmail } from "app/service/email/welcome"; 4 | import { NextRequest, NextResponse } from "next/server"; 5 | 6 | export async function POST(req: NextRequest) { 7 | const { name, email, password, passwordConfirm } = await req.json(); 8 | 9 | await create({ 10 | name, 11 | email, 12 | password, 13 | passwordConfirm, 14 | }); 15 | 16 | sendWelcomeEmail(name, email); 17 | sendVerificationEmail(name, email); 18 | 19 | return NextResponse.json({ message: "Create user" }); 20 | } 21 | -------------------------------------------------------------------------------- /src/app/api/users/avatar/route.ts: -------------------------------------------------------------------------------- 1 | import { put } from "@vercel/blob"; 2 | import { get, update } from "app/repository/user"; 3 | import { auth } from "auth"; 4 | 5 | export const POST = auth(async (req) => { 6 | if (!req.auth || !req.auth.user) { 7 | return Response.json({ message: "Unauthorized" }, { status: 401 }); 8 | } 9 | 10 | const { user } = req.auth; 11 | 12 | const dbUser = await get({ email: user.email as string }); 13 | 14 | const formData = await req.formData(); 15 | 16 | const image = formData.get("image"); 17 | 18 | const { name: filename } = image as File; 19 | 20 | if (!image) { 21 | return Response.json({ error: "Image is required" }, { status: 400 }); 22 | } 23 | 24 | if (!req.body) { 25 | return Response.json({ message: "Body is required" }, { status: 400 }); 26 | } 27 | 28 | const buffer = Buffer.from(await (image as Blob).arrayBuffer()); 29 | 30 | try { 31 | const blob = await put(`avatars/${dbUser.id}-${filename}`, buffer, { 32 | access: "public", 33 | }); 34 | return Response.json({ 35 | url: blob.url, 36 | }); 37 | } catch (e) { 38 | console.log(e); 39 | return Response.json( 40 | { message: "Fail to upload user avatar using vercel/blob" }, 41 | { status: 500 } 42 | ); 43 | } 44 | }); 45 | 46 | export const PUT = auth(async (req) => { 47 | if (!req.auth || !req.auth.user) { 48 | return Response.json({ message: "Unauthorized" }, { status: 401 }); 49 | } 50 | 51 | const { user } = req.auth; 52 | 53 | const dbUser = await get({ email: user.email as string }); 54 | 55 | const { image } = await req.json(); 56 | 57 | if (!image) { 58 | return Response.json({ error: "Image url is required" }, { status: 400 }); 59 | } 60 | 61 | try { 62 | await update({ 63 | id: dbUser.id, 64 | image, 65 | }); 66 | return Response.json({ message: "User updated" }, { status: 201 }); 67 | } catch (e) { 68 | console.log(e); 69 | return Response.json({ message: "Fail to update user" }, { status: 500 }); 70 | } 71 | }); 72 | -------------------------------------------------------------------------------- /src/app/api/users/resetPassword/route.ts: -------------------------------------------------------------------------------- 1 | import { resetPassword } from "app/repository/user"; 2 | import { NextRequest, NextResponse } from "next/server"; 3 | 4 | export const POST = async (req: NextRequest) => { 5 | const { token, password, passwordConfirm } = await req.json(); 6 | 7 | try { 8 | await resetPassword({ 9 | token, 10 | password, 11 | passwordConfirm, 12 | }); 13 | 14 | return NextResponse.json({ message: "Password reset" }); 15 | } catch (e) { 16 | return NextResponse.json( 17 | { message: (e as Error).message }, 18 | { status: 400 } 19 | ); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/app/api/users/route.ts: -------------------------------------------------------------------------------- 1 | import { NextResponse } from "next/server"; 2 | import { list } from "app/repository/user"; 3 | import { auth } from "auth"; 4 | 5 | export const GET = auth(async (req) => { 6 | if (req.auth) { 7 | const users = await list(); 8 | return NextResponse.json(users); 9 | } 10 | 11 | return Response.json({ message: "Not authenticated" }, { status: 401 }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/api/users/sendResetPasswordEmail/route.ts: -------------------------------------------------------------------------------- 1 | import { sendResetPasswordEmail } from "app/service/email/resetPassword"; 2 | import { NextRequest, NextResponse } from "next/server"; 3 | 4 | export const POST = async (req: NextRequest) => { 5 | const { email } = await req.json(); 6 | 7 | await sendResetPasswordEmail(email); 8 | 9 | return NextResponse.json({ message: "Email sent" }); 10 | }; 11 | -------------------------------------------------------------------------------- /src/app/api/verify/route.ts: -------------------------------------------------------------------------------- 1 | import { verifyEmailToken } from "app/repository/verification"; 2 | import { NextRequest, NextResponse } from "next/server"; 3 | 4 | export const POST = async (req: NextRequest) => { 5 | const { token } = await req.json(); 6 | 7 | try { 8 | await verifyEmailToken(token); 9 | 10 | return NextResponse.json({ message: "Verified user" }); 11 | } catch (e) { 12 | return NextResponse.json( 13 | { message: (e as Error).message }, 14 | { status: 400 } 15 | ); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dannyisadog/nextjs-authentication-template/25c90b3b0ae18fcef0b9db3c20871c8519d16158/src/app/favicon.ico -------------------------------------------------------------------------------- /src/app/forgotPassword/page.tsx: -------------------------------------------------------------------------------- 1 | import SendForgotPasswordLinkForm from "components/client/SendForgotPasswordLinkForm"; 2 | import Title from "components/client/Title"; 3 | 4 | export default async function Signin() { 5 | return ( 6 | <> 7 |
Hi {firstName},
23 |24 | We received a request to reset your password. If you didn{"'"}t make 25 | the request, you can ignore this email. 26 |
27 |
33 | Best,
34 |
35 | Nextjs Authjs Template Team
36 |
Hi {firstName},
20 |
21 | Welcome to the Next.js Auth.js Template!
22 |
23 | We{"'"}re thrilled to have you with us!
24 |
34 | Best,
35 |
36 | Nextjs Authjs Template Team
37 |
Hi {firstName},
22 |
23 | Welcome to the Next.js Auth.js Template!
24 |
25 | Please verify your email by clicking the button below.
26 |
33 | Best,
34 |
35 | Next.js Authentication Template Team
36 |