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

Fix with-firebase-authentication example: Update the cookie when ID token refreshes on client #15628

Merged
16 changes: 4 additions & 12 deletions examples/with-firebase-authentication/components/FirebaseAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { useEffect, useState } from 'react'
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'
import firebase from 'firebase/app'
import 'firebase/auth'
import cookie from 'js-cookie'
import initFirebase from '../utils/auth/initFirebase'
import { setUserCookie } from '../utils/auth/userCookies'
import { mapUserData } from '../utils/auth/mapUserData'

// Init the Firebase app.
initFirebase()
Expand All @@ -23,17 +24,8 @@ const firebaseAuthConfig = {
credentialHelper: 'none',
callbacks: {
signInSuccessWithAuthResult: async ({ user }, redirectUrl) => {
// xa is the access token, which can be retrieved through
// firebase.auth().currentUser.getIdToken()
const { uid, email, xa } = user
const userData = {
id: uid,
email,
token: xa,
}
cookie.set('auth', userData, {
expires: 1,
})
const userData = mapUserData(user)
setUserCookie(userData)
},
},
}
Expand Down
2 changes: 1 addition & 1 deletion examples/with-firebase-authentication/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const Index = () => {
</Link>
</div>
{error && <div>Failed to fetch food!</div>}
{data ? (
{data && !error ? (
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a tiny UI bug - when an error happened it still showed "Loading..." as well as "Failed to fetch food!"

<div>Your favorite food is {data.food}.</div>
) : (
<div>Loading...</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const mapUserData = (user) => {
const { uid, email, xa } = user
return {
id: uid,
email,
token: xa,
}
}
29 changes: 23 additions & 6 deletions examples/with-firebase-authentication/utils/auth/useUser.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { useEffect, useState } from 'react'
import { useRouter } from 'next/router'
import cookies from 'js-cookie'
import firebase from 'firebase/app'
import 'firebase/auth'
import initFirebase from '../auth/initFirebase'
import {
removeUserCookie,
setUserCookie,
getUserFromCookie,
} from './userCookies'
import { mapUserData } from './mapUserData'

initFirebase()

Expand All @@ -17,8 +22,6 @@ const useUser = () => {
.signOut()
.then(() => {
// Sign-out successful.
cookies.remove('auth')
setUser()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This happens automatically via the onIdTokenChanged below, so no need to duplicate it here.

router.push('/auth')
})
.catch((e) => {
Expand All @@ -27,12 +30,26 @@ const useUser = () => {
}

useEffect(() => {
const cookie = cookies.get('auth')
if (!cookie) {
// Firebase updates the id token every hour, this
// makes sure the react state and the cookie are
// both kept up to date
firebase.auth().onIdTokenChanged((user) => {
if (user) {
const userData = mapUserData(user)
setUserCookie(userData)
setUser(userData)
} else {
removeUserCookie()
setUser()
}
})

const userFromCookie = getUserFromCookie()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the user retrieval from the cookie that existed before. It's not really necessary now, as it will be handled by onIdTokenChanged above, but I've left it in because I think it's a bit quicker to load than the firebase client library is 🤷‍♂️

if (!userFromCookie) {
router.push('/')
return
}
setUser(JSON.parse(cookie))
setUser(userFromCookie)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

Expand Down
19 changes: 19 additions & 0 deletions examples/with-firebase-authentication/utils/auth/userCookies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import cookies from 'js-cookie'

export const getUserFromCookie = () => {
const cookie = cookies.get('auth')
if (!cookie) {
return
}
return JSON.parse(cookie)
}

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

export const removeUserCookie = () => cookies.remove('auth')