├── .eslintrc.json ├── .env ├── src └── app │ ├── globals.css │ ├── favicon.ico │ ├── SessionProvider.tsx │ ├── layout.tsx │ ├── page.tsx │ ├── firebase.ts │ ├── forgot-password │ └── page.tsx │ ├── signin │ └── page.tsx │ └── signup │ └── page.tsx ├── next.config.js ├── postcss.config.js ├── .gitignore ├── tailwind.config.js ├── public ├── vercel.svg └── next.svg ├── package.json ├── tsconfig.json ├── pages └── api │ └── auth │ └── [...nextauth].ts └── README.md /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | NEXTAUTH_URL=http://localhost:3000 2 | NEXTAUTH_SECRET=SuperSecret 3 | -------------------------------------------------------------------------------- /src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jimbeck/nextjs-firebase-username-password/HEAD/src/app/favicon.ico -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {} 3 | 4 | module.exports = nextConfig 5 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /src/app/SessionProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { SessionProvider as Provider } from 'next-auth/react'; 3 | 4 | type Props = { 5 | children: React.ReactNode; 6 | } 7 | 8 | export default function SessionProvider({children}: Props) { 9 | return ( 10 | 11 | {children} 12 | 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import './globals.css' 2 | import SessionProvider from './SessionProvider'; 3 | 4 | 5 | export default async function RootLayout({ 6 | children, 7 | }: { 8 | children: React.ReactNode 9 | }) { 10 | return ( 11 | 12 | 13 | 14 | {children} 15 | 16 | 17 | 18 | ) 19 | } -------------------------------------------------------------------------------- /.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 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /src/app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { signOut, useSession } from 'next-auth/react'; 3 | import { redirect } from 'next/navigation'; 4 | 5 | export default function Home() { 6 | const session = useSession({ 7 | required: true, 8 | onUnauthenticated() { 9 | redirect('/signin'); 10 | }, 11 | }); 12 | return ( 13 |
14 |
{session?.data?.user?.email }
15 | 16 |
17 | ) 18 | } 19 | 20 | Home.requireAuth = true -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | './src/pages/**/*.{js,ts,jsx,tsx,mdx}', 5 | './src/components/**/*.{js,ts,jsx,tsx,mdx}', 6 | './src/app/**/*.{js,ts,jsx,tsx,mdx}', 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 12 | 'gradient-conic': 13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', 14 | }, 15 | }, 16 | }, 17 | plugins: [ 18 | require('@tailwindcss/forms'), 19 | ], 20 | } 21 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@tailwindcss/forms": "^0.5.3", 13 | "@types/node": "20.2.5", 14 | "@types/react": "18.2.7", 15 | "@types/react-dom": "18.2.4", 16 | "autoprefixer": "10.4.14", 17 | "eslint": "8.41.0", 18 | "eslint-config-next": "13.4.4", 19 | "firebase": "^9.23.0", 20 | "next": "13.4.4", 21 | "next-auth": "^4.22.1", 22 | "postcss": "8.4.24", 23 | "react": "18.2.0", 24 | "react-dom": "18.2.0", 25 | "tailwindcss": "3.3.2", 26 | "typescript": "5.0.4" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "plugins": [ 18 | { 19 | "name": "next" 20 | } 21 | ], 22 | "paths": { 23 | "@/*": ["./src/*"] 24 | } 25 | }, 26 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /src/app/firebase.ts: -------------------------------------------------------------------------------- 1 | import { getApp, getApps, initializeApp } from "firebase/app"; 2 | import { getAuth } from "firebase/auth"; 3 | import { getFirestore, } from 'firebase/firestore'; 4 | // TODO: Add SDKs for Firebase products that you want to use 5 | // https://firebase.google.com/docs/web/setup#available-libraries 6 | 7 | // Your web app's Firebase configuration 8 | const firebaseConfig = { 9 | apiKey: "AIzaSyAtk_PO-mC9xEZsN8aatyEHdLFkZvt_hTo", 10 | authDomain: "next-auth-username-passwords.firebaseapp.com", 11 | projectId: "next-auth-username-passwords", 12 | storageBucket: "next-auth-username-passwords.appspot.com", 13 | messagingSenderId: "78794701925", 14 | appId: "1:78794701925:web:d1baa091db025a1da61a8c" 15 | }; 16 | 17 | // Initialize Firebase 18 | const app = getApps().length ? getApp() : initializeApp(firebaseConfig); 19 | const db = getFirestore(); 20 | const auth = getAuth(); 21 | 22 | export { app, db, auth } -------------------------------------------------------------------------------- /pages/api/auth/[...nextauth].ts: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth" 2 | import CredentialsProvider from "next-auth/providers/credentials"; 3 | import {signInWithEmailAndPassword} from 'firebase/auth'; 4 | import { auth } from "@/app/firebase"; 5 | 6 | 7 | export const authOptions = { 8 | // Configure one or more authentication providers 9 | pages: { 10 | signIn: '/signin' 11 | }, 12 | providers: [ 13 | CredentialsProvider({ 14 | name: 'Credentials', 15 | credentials: {}, 16 | async authorize(credentials): Promise { 17 | return await signInWithEmailAndPassword(auth, (credentials as any).email || '', (credentials as any).password || '') 18 | .then(userCredential => { 19 | if (userCredential.user) { 20 | return userCredential.user; 21 | } 22 | return null; 23 | }) 24 | .catch(error => (console.log(error))) 25 | .catch((error) => { 26 | const errorCode = error.code; 27 | const errorMessage = error.message; 28 | console.log(error); 29 | }); 30 | } 31 | }) 32 | ], 33 | } 34 | export default NextAuth(authOptions) -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 18 | 19 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /src/app/forgot-password/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { useState } from 'react'; 3 | import { auth } from '../firebase'; 4 | import { sendPasswordResetEmail } from "firebase/auth"; 5 | 6 | export default function ForgotPassword() { 7 | const [email, setEmail] = useState(''); 8 | 9 | const resetEmail = () => { 10 | sendPasswordResetEmail(auth, email); 11 | }; 12 | 13 | return ( 14 | <> 15 |
16 |
17 | Your Company 22 |

23 | Forgot Password 24 |

25 |
26 | 27 |
28 |
29 |
30 | 33 |
34 | setEmail(e.target.value)} 40 | required 41 | className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" 42 | /> 43 |
44 |
45 | 46 |
47 | 54 |
55 |
56 |
57 |
58 | 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /src/app/signin/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { signIn } from 'next-auth/react'; 3 | import { useRouter } from 'next/navigation'; 4 | import { useState } from 'react'; 5 | 6 | export default function Signin() { 7 | const [email, setEmail] = useState(''); 8 | const [password, setPassword] = useState(''); 9 | const router = useRouter(); 10 | return ( 11 | <> 12 |
13 |
14 | Your Company 19 |

20 | Sign in to your account 21 |

22 |
23 | 24 |
25 |
26 |
27 | 30 |
31 | setEmail(e.target.value)} 37 | required 38 | className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" 39 | /> 40 |
41 |
42 | 43 |
44 |
45 | 48 |
49 |
router.push('/forgot-password')} className="cursor-pointer font-semibold text-indigo-400 hover:text-indigo-300"> 50 | Forgot password? 51 |
52 |
53 |
54 |
55 | setPassword(e.target.value)} 61 | required 62 | className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" 63 | /> 64 |
65 |
66 | 67 |
68 | 75 |
76 |
77 | 78 |

79 | Not a member?{' '} 80 | 83 |

84 |
85 |
86 | 87 | ) 88 | } 89 | -------------------------------------------------------------------------------- /src/app/signup/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import { createUserWithEmailAndPassword } from 'firebase/auth'; 3 | import { useRouter } from 'next/navigation'; 4 | import { useState } from 'react'; 5 | import { auth } from '../firebase'; 6 | 7 | export default function Signup() { 8 | const [email, setEmail] = useState(''); 9 | const [password, setPassword] = useState(''); 10 | const [passwordAgain, setPasswordAgain] = useState(''); 11 | 12 | const signup = () => { 13 | createUserWithEmailAndPassword(auth, email, password); 14 | }; 15 | 16 | return ( 17 | <> 18 |
19 |
20 | Your Company 25 |

26 | Sign up 27 |

28 |
29 | 30 |
31 |
32 |
33 | 36 |
37 | setEmail(e.target.value)} 43 | required 44 | className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" 45 | /> 46 |
47 |
48 | 49 |
50 |
51 | 54 |
55 |
56 | setPassword(e.target.value)} 62 | required 63 | className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" 64 | /> 65 |
66 |
67 |
68 |
69 | 72 |
73 |
74 | setPasswordAgain(e.target.value)} 80 | required 81 | className="block w-full rounded-md border-0 bg-white/5 py-1.5 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6" 82 | /> 83 |
84 |
85 | 86 |
87 | 94 |
95 |
96 |
97 |
98 | 99 | ) 100 | } 101 | --------------------------------------------------------------------------------