├── .gitignore ├── README.md ├── components └── Button.js ├── initAuth.js ├── jsconfig.json ├── next.config.js ├── package.json ├── pages ├── _app.js ├── api │ ├── login.js │ └── logout.js ├── auth.js ├── demo.js └── index.js ├── public ├── favicon.ico ├── panda-bear-gordo.jpg └── vercel.svg └── styles ├── Home.module.css └── globals.css /.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 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Next.js Firebase Auth 2 | 3 | Needed ENVIRONMENT VARIABLES: 4 | 5 | `COOKIE_SECRET_CURRENT` 6 | `COOKIE_SECRET_PREVIOUS` 7 | `FIREBASE_PRIVATE_KEY` -------------------------------------------------------------------------------- /components/Button.js: -------------------------------------------------------------------------------- 1 | export default function Button () { 2 | return 5 | } -------------------------------------------------------------------------------- /initAuth.js: -------------------------------------------------------------------------------- 1 | import { init } from 'next-firebase-auth' 2 | 3 | const initAuth = () => { 4 | init({ 5 | authPageURL: '/auth', 6 | appPageURL: '/', 7 | loginAPIEndpoint: '/api/login', // required 8 | logoutAPIEndpoint: '/api/logout', // required 9 | firebaseAdminInitConfig: { 10 | credential: { 11 | projectId: 'meneadev', 12 | clientEmail: 'firebase-adminsdk-qdn79@meneadev.iam.gserviceaccount.com', 13 | // The private key must not be accesssible on the client side. 14 | privateKey: process.env.FIREBASE_PRIVATE_KEY, 15 | } 16 | }, 17 | firebaseClientInitConfig: { 18 | apiKey: "AIzaSyBY-RUdvehNuwOFF6NM_g0_SenOxsfAd8A", 19 | authDomain: "meneadev.firebaseapp.com", 20 | projectId: "meneadev", 21 | storageBucket: "meneadev.appspot.com", 22 | messagingSenderId: "315195767367", 23 | appId: "1:315195767367:web:07ccc6fa7e00ceb13a4f62", 24 | measurementId: "G-N318HL6NF0" 25 | }, 26 | cookies: { 27 | name: 'midu-cookie-app', // required 28 | // Keys are required unless you set `signed` to `false`. 29 | // The keys cannot be accessible on the client side. 30 | keys: [ 31 | process.env.COOKIE_SECRET_CURRENT, 32 | process.env.COOKIE_SECRET_PREVIOUS, 33 | ], 34 | httpOnly: true, 35 | maxAge: 12 * 60 * 60 * 24 * 1000, // twelve days 36 | overwrite: true, 37 | path: '/', 38 | sameSite: 'strict', 39 | secure: true, // set this to false in local (non-HTTPS) development 40 | signed: true, 41 | }, 42 | }) 43 | } 44 | 45 | export default initAuth -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./" 4 | } 5 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | images: { 3 | domains: ['avatars.githubusercontent.com'], 4 | }, 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-firebase-auth", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "firebase": "^8.6.8", 12 | "firebase-admin": "^9.9.0", 13 | "next": "11.0.1", 14 | "next-firebase-auth": "0.13.1", 15 | "react": "17.0.2", 16 | "react-dom": "17.0.2", 17 | "react-firebaseui": "^5.0.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import initAuth from '../initAuth' 3 | 4 | initAuth() 5 | 6 | function MyApp({ Component, pageProps }) { 7 | return 8 | } 9 | 10 | export default MyApp 11 | -------------------------------------------------------------------------------- /pages/api/login.js: -------------------------------------------------------------------------------- 1 | import { setAuthCookies } from "next-firebase-auth" 2 | import initAuth from "initAuth.js" 3 | 4 | initAuth() 5 | 6 | export default async function handler (req, res) { 7 | try { 8 | await setAuthCookies(req, res) 9 | } catch (e) { 10 | console.error(e) 11 | return res.status(500).json({ error: 'Unexpected error.' }) 12 | } 13 | return res.status(200).json({ success: true }) 14 | } 15 | -------------------------------------------------------------------------------- /pages/api/logout.js: -------------------------------------------------------------------------------- 1 | import { unsetAuthCookies } from 'next-firebase-auth' 2 | import initAuth from 'initAuth.js' // the module you created above 3 | 4 | initAuth() 5 | 6 | export default async function handler (req, res) { 7 | try { 8 | await unsetAuthCookies(req, res) 9 | } catch (e) { 10 | return res.status(500).json({ error: 'Unexpected error.' }) 11 | } 12 | return res.status(200).json({ success: true }) 13 | } -------------------------------------------------------------------------------- /pages/auth.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import firebase from 'firebase/app' 3 | import 'firebase/auth' 4 | import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth' 5 | import { AuthAction, withAuthUser } from 'next-firebase-auth' 6 | 7 | const firebaseAuthConfig = { 8 | signInFlow: 'popup', 9 | // Auth providers 10 | // https://github.com/firebase/firebaseui-web#configure-oauth-providers 11 | signInOptions: [ 12 | { 13 | provider: firebase.auth.EmailAuthProvider.PROVIDER_ID, 14 | requireDisplayName: false, 15 | }, 16 | { 17 | provider: firebase.auth.GithubAuthProvider.PROVIDER_ID, 18 | } 19 | ], 20 | signInSuccessUrl: '/', 21 | credentialHelper: 'none', 22 | callbacks: { 23 | // https://github.com/firebase/firebaseui-web#signinsuccesswithauthresultauthresult-redirecturl 24 | signInSuccessWithAuthResult: () => 25 | // Don't automatically redirect. We handle redirecting based on 26 | // auth state in withAuthComponent.js. 27 | false, 28 | }, 29 | } 30 | 31 | function Auth () { 32 | const [renderAuth, setRenderAuth] = useState(false) 33 | useEffect(() => { 34 | setRenderAuth(true) 35 | }, []) 36 | 37 | return ( 38 |
39 | {renderAuth ? ( 40 | 44 | ) : null} 45 |
46 | ) 47 | } 48 | 49 | export default withAuthUser({ 50 | whenAuthed: AuthAction.REDIRECT_TO_APP 51 | })(Auth) -------------------------------------------------------------------------------- /pages/demo.js: -------------------------------------------------------------------------------- 1 | import { 2 | AuthAction, 3 | useAuthUser, 4 | withAuthUser, // High Order Component -> función que devuelve un componente 5 | withAuthUserTokenSSR, // High Order Function -> función que devuelve una función 6 | } from 'next-firebase-auth' 7 | import firebase from 'firebase' 8 | import Image from 'next/image' 9 | import Button from 'components/Button.js' 10 | import pandaImageSrc from 'public/panda-bear-gordo.jpg' 11 | 12 | const Demo = () => { 13 | const user = useAuthUser() 14 | console.log({user}) 15 | 16 | return ( 17 |
18 | 19 | 20 | Panda bear gordito y acolchadito 21 | 22 |
23 | 24 |
25 |

Your email is {user.email ? user.email : "unknown"}.

26 | 27 |
28 | ) 29 | } 30 | 31 | // Note that this is a higher-order function. 32 | export const getServerSideProps = withAuthUserTokenSSR({ 33 | whenUnauthed: AuthAction.REDIRECT_TO_LOGIN 34 | })(() => { 35 | return { 36 | props: {} 37 | } 38 | }) 39 | 40 | export default withAuthUser({ 41 | whenUnauthedAfterInit: AuthAction.REDIRECT_TO_LOGIN 42 | })(Demo) -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import { withAuthUser, useAuthUser } from 'next-firebase-auth' 2 | import Head from 'next/head' 3 | import Image from 'next/image' 4 | import styles from '../styles/Home.module.css' 5 | 6 | function Home() { 7 | const user = useAuthUser() 8 | console.log(user.id) 9 | 10 | return ( 11 |
12 |

Estoy haciendo Auth para Next.js con Firebase 👋

13 |
14 | ) 15 | } 16 | 17 | export default withAuthUser()(Home) -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/next-firebase-auth/9b6c99a2adb177aace439d14118536373cf14344/public/favicon.ico -------------------------------------------------------------------------------- /public/panda-bear-gordo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/midudev/next-firebase-auth/9b6c99a2adb177aace439d14118536373cf14344/public/panda-bear-gordo.jpg -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | min-height: 100vh; 3 | padding: 0 0.5rem; 4 | display: flex; 5 | flex-direction: column; 6 | justify-content: center; 7 | align-items: center; 8 | height: 100vh; 9 | } 10 | 11 | .main { 12 | padding: 5rem 0; 13 | flex: 1; 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: center; 17 | align-items: center; 18 | } 19 | 20 | .footer { 21 | width: 100%; 22 | height: 100px; 23 | border-top: 1px solid #eaeaea; 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | } 28 | 29 | .footer a { 30 | display: flex; 31 | justify-content: center; 32 | align-items: center; 33 | flex-grow: 1; 34 | } 35 | 36 | .title a { 37 | color: #0070f3; 38 | text-decoration: none; 39 | } 40 | 41 | .title a:hover, 42 | .title a:focus, 43 | .title a:active { 44 | text-decoration: underline; 45 | } 46 | 47 | .title { 48 | margin: 0; 49 | line-height: 1.15; 50 | font-size: 4rem; 51 | } 52 | 53 | .title, 54 | .description { 55 | text-align: center; 56 | } 57 | 58 | .description { 59 | line-height: 1.5; 60 | font-size: 1.5rem; 61 | } 62 | 63 | .code { 64 | background: #fafafa; 65 | border-radius: 5px; 66 | padding: 0.75rem; 67 | font-size: 1.1rem; 68 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 69 | Bitstream Vera Sans Mono, Courier New, monospace; 70 | } 71 | 72 | .grid { 73 | display: flex; 74 | align-items: center; 75 | justify-content: center; 76 | flex-wrap: wrap; 77 | max-width: 800px; 78 | margin-top: 3rem; 79 | } 80 | 81 | .card { 82 | margin: 1rem; 83 | padding: 1.5rem; 84 | text-align: left; 85 | color: inherit; 86 | text-decoration: none; 87 | border: 1px solid #eaeaea; 88 | border-radius: 10px; 89 | transition: color 0.15s ease, border-color 0.15s ease; 90 | width: 45%; 91 | } 92 | 93 | .card:hover, 94 | .card:focus, 95 | .card:active { 96 | color: #0070f3; 97 | border-color: #0070f3; 98 | } 99 | 100 | .card h2 { 101 | margin: 0 0 1rem 0; 102 | font-size: 1.5rem; 103 | } 104 | 105 | .card p { 106 | margin: 0; 107 | font-size: 1.25rem; 108 | line-height: 1.5; 109 | } 110 | 111 | .logo { 112 | height: 1em; 113 | margin-left: 0.5rem; 114 | } 115 | 116 | @media (max-width: 600px) { 117 | .grid { 118 | width: 100%; 119 | flex-direction: column; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | --------------------------------------------------------------------------------