Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add firebase auth #476

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Update these with your Firebase app's values.
[email protected]
NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY=AIzaSyACwDFTZ20uN49ZJ-Rvs5d2tci3HR4jWDc
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=schoenworld-timeline.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=schoenworld-timeline
5 changes: 5 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Update these with your Firebase app's values.
[email protected]
NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY=AIzaSyACwDFTZ20uN49ZJ-Rvs5d2tci3HR4jWDc
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=schoenworld-timeline.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=schoenworld-timeline
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ out/
node_modules/
next-env.d.ts
_serverless
.env.local
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ node_modules
build
out
.next
.env
storybook-static
24 changes: 15 additions & 9 deletions app/components/ContentfulLink/ContentfulLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { A } from '../Typography'
import { CONTENTFUL_SPACE_ID } from '../../data/constants'
import { shades } from '../../data/colors'
import { useTranslation } from '../../hooks/useTranslation'
import { useUser } from '../../hooks/useUser'

interface ContentfulLinkProps {
id: string
Expand All @@ -16,14 +17,19 @@ const StyledA = styled(A)`

export const ContentfulLink: React.FC<ContentfulLinkProps> = ({ id }) => {
const { t } = useTranslation()
const { user } = useUser()

return (
<StyledA
href={`https://app.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/entries/${id}`}
target="_blank"
rel="noopener noreferrer"
>
{t('misc.contentfulEdit')}
</StyledA>
)
if (user) {
return (
<StyledA
href={`https://app.contentful.com/spaces/${CONTENTFUL_SPACE_ID}/entries/${id}`}
target="_blank"
rel="noopener noreferrer"
>
{t('misc.contentfulEdit')}
</StyledA>
)
}

return null
}
32 changes: 32 additions & 0 deletions app/components/FirebaseAuth/FirebaseAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'
import firebase from 'firebase/app'
import 'firebase/auth'
import { initFirebase } from '../../utils/initFirebase'
import { setUserCookie } from '../../utils/userCookies'
import { mapUserData } from '../../utils/mapUserData'

// Init the Firebase app.
initFirebase()

// Configure FirebaseUI.
const uiConfig = {
// Popup signin flow rather than redirect flow.
signInFlow: 'popup',
// Redirect to /signedIn after sign in is successful. Alternatively you can provide a callbacks.signInSuccess function.
signInSuccessUrl: '/',
// We will display Google and Facebook as auth providers.
signInOptions: [firebase.auth.GithubAuthProvider.PROVIDER_ID],
signInSuccess: async ({ user }) => {
const userData = await mapUserData(user)
setUserCookie(userData)
},
}

export const FirebaseAuth = () => {
return (
<div>
<StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={firebase.auth()} />
</div>
)
}
1 change: 1 addition & 0 deletions app/components/FirebaseAuth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './FirebaseAuth'
75 changes: 75 additions & 0 deletions app/hooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import firebase from 'firebase/app'
import 'firebase/auth'

import { initFirebase } from '../utils/initFirebase'
import {
removeUserCookie,
setUserCookie,
getUserFromCookie,
} from '../utils/userCookies'

import { mapUserData } from '../utils/mapUserData'

initFirebase()

type UserType = {
id: string
email: string
token: string
}

const useUser = () => {
const [user, setUser] = useState<UserType | undefined>()
const router = useRouter()

const logout = async () => {
return firebase
.auth()
.signOut()
.then(() => {
// Sign-out successful.
router.push('/auth')
})
.catch(e => {
console.error(e)
})
}

useEffect(() => {
// Firebase updates the id token every hour, this
// makes sure the react state and the cookie are
// both kept up to date
const cancelAuthListener = firebase
.auth()
.onIdTokenChanged(async fireUser => {
if (fireUser) {
console.log(fireUser)
const userData = await mapUserData(fireUser)
setUserCookie(userData)
setUser(userData)
} else {
removeUserCookie()
setUser(undefined)
}
})

const userFromCookie = getUserFromCookie()
if (!userFromCookie) {
router.push('/')
return
}
setUser(userFromCookie)

// eslint-disable-next-line consistent-return
return () => {
cancelAuthListener()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

return { user, logout }
}

export { useUser }
15 changes: 15 additions & 0 deletions app/utils/initFirebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import firebase from 'firebase/app'
import 'firebase/auth'

const config = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
}

export const initFirebase = () => {
if (!firebase.apps.length) {
firebase.initializeApp(config)
}
}
12 changes: 12 additions & 0 deletions app/utils/mapUserData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const mapUserData = async user => {
const { uid, email, photoURL } = user

const token = await user.getIdToken(true)

return {
id: uid,
email,
token,
photoURL,
}
}
22 changes: 22 additions & 0 deletions app/utils/userCookies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { createCookie, eraseCookie, readCookie } from '../js/cookie'

export const getUserFromCookie = () => {
const cookie = readCookie('auth')

if (!cookie) {
return
}

// eslint-disable-next-line consistent-return
return JSON.parse(cookie)
}

export const setUserCookie = user => {
createCookie('auth', JSON.stringify(user), {
// firebase id tokens expire in one hour
// set cookie expiry to match
maxAgeInDays: 1 / 24,
})
}

export const removeUserCookie = () => eraseCookie('auth')
Loading