-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
21 changed files
with
10,317 additions
and
5,448 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Environment variables for firebase-admin | ||
FIREBASE_PROJECT_ID=required | ||
FIREBASE_PRIVATE_KEY=required | ||
FIREBASE_CLIENT_EMAIL=required | ||
FIREBASE_DATABASE_URL=if needed, see initAuth in /app/components/auth/firebase/lib/functions.js | ||
|
||
# Environment variables for firebase client config. | ||
NEXT_PUBLIC_FIREBASE_PROJECT_ID=required | ||
NEXT_PUBLIC_FIREBASE_API_KEY=required | ||
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=required | ||
NEXT_PUBLIC_FIREBASE_APP_ID=required | ||
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET= | ||
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= | ||
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID= | ||
|
||
# for cookies signing | ||
COOKIE_SECRET_CURRENT= | ||
COOKIE_SECRET_PREVIOUS= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { FaUser } from "react-icons/fa"; | ||
|
||
export function NoUserAvatar({size,name}){ | ||
const char = name ? name.charAt(0) : null; | ||
return ( | ||
<div | ||
className="d-flex justify-content-center align-items-center" | ||
style={{ | ||
width: `${size}px`, | ||
height: `${size}px`, | ||
background: "#dee2e6", | ||
borderRadius: "50%" | ||
}}> | ||
{ | ||
char ? | ||
<span style={{fontSize: `${size*0.65}px`}}>{char}</span> | ||
: | ||
<FaUser size={`${size*0.45}px`}/> | ||
} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
### Set up | ||
|
||
1. set up environment variables for firebase config in `.env.local` | ||
|
||
``` | ||
# Environment variables for firebase-admin. | ||
# You can also find these values in the service-key.json file that you downloaded from firebase. | ||
FIREBASE_PROJECT_ID=required | ||
FIREBASE_PRIVATE_KEY=required | ||
FIREBASE_CLIENT_EMAIL=required | ||
FIREBASE_DATABASE_URL=if needed, see initAuth in /app/components/auth/firebase/lib/functions.js | ||
# Environment variables for firebase client config. | ||
NEXT_PUBLIC_FIREBASE_PROJECT_ID=required | ||
NEXT_PUBLIC_FIREBASE_API_KEY=required | ||
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=required | ||
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET= | ||
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= | ||
NEXT_PUBLIC_FIREBASE_APP_ID=required | ||
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID= | ||
# for cookies signing | ||
COOKIE_SECRET_CURRENT=example_string_feafh3r2rv4ty4893vyt5vt5t38vy5n9t5vyt8vn54 | ||
COOKIE_SECRET_PREVIOUS=example_string_u4ht83r3m20rxc34nty340v9t4ty340mtu438ty48ntv4y8v | ||
``` | ||
2. Initialize `next-firebase-auth` in _app.js | ||
``` | ||
// ./pages/_app.js | ||
import { initAuth } from '../components/auth/firebase'; | ||
initAuth() | ||
.. | ||
.. | ||
``` | ||
3. Export the page component with `withAuthUser(Page)` and use `useAuthUser()` hook to get user info. | ||
``` | ||
// ./pages/demo | ||
import React from 'react' | ||
import { | ||
useAuthUser, | ||
withAuthUser, | ||
} from 'next-firebase-auth' | ||
const Demo = () => { | ||
const AuthUser = useAuthUser() | ||
return ( | ||
<div> | ||
<p>Your email is {AuthUser.email ? AuthUser.email : 'unknown'}.</p> | ||
</div> | ||
) | ||
} | ||
export default withAuthUser()(Demo) | ||
``` | ||
4. For SSR, use `withAuthUserSSR` to wrap your getServerSideProps. | ||
|
||
``` | ||
export const getServerSideProps = withAuthUserSSR(options)(({AuthUser}) => { }) | ||
``` | ||
|
||
For more details, see [https://github.com/gladly-team/next-firebase-auth](https://github.com/gladly-team/next-firebase-auth) | ||
|
||
5. The `AuthUI` component handles UI for login and signup. | ||
|
||
6. To use in development env. Set, `secure: false` in cookies config in `initAuth` function in file `/app/components/auth/firebase/lib/functions.js` | ||
|
||
``` | ||
cookies: { | ||
... | ||
.... | ||
sameSite: 'strict', | ||
secure: false, // set this to false in local (non-HTTPS) development | ||
signed: true, | ||
}, | ||
``` | ||
7. Build will fail if environment variables are not set. In order not to affect rendering of other components make use of `withFirebaseAuthUser`, `withFirebaseAuthUserSSR`, `withFirebaseAuthUserTokenSSR` and `useFirebaseAuthUser` instead of their respective `next-firebase-auth` version. They are just a wrapper that checks if firebase is initialised properly or not. And prevents build fail. They are exported from `/app/components/auth/firebase`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import functions from "./lib/functions"; | ||
import firebaseAuthMenuButtonModule from "./ui/FirebaseAuthMenuButton"; | ||
import firebaseAuthUIModule from "./ui/FirebaseAuthUI"; | ||
import firebaseLogimFormModule from "./ui/FirebaseLoginForm"; | ||
import firebaseSignupFormModule from "./ui/FirebaseSignupForm"; | ||
import firebaseUserInfoModule from "./ui/FirebaseUserInfo"; | ||
|
||
export const withFirebaseAuthUser = functions.withFirebaseAuthUser; | ||
export const withFirebaseAuthUserSSR = functions.withFirebaseAuthUserSSR; | ||
export const withFirebaseAuthUserTokenSSR = functions.withFirebaseAuthUserTokenSSR; | ||
export const useFirebaseAuthUser = functions.useFirebaseAuthUser; | ||
export const getInitAuthResult = functions.getInitAuthResult; | ||
export const initAuth = functions.initAuth; | ||
export const createEmptyAuthUser = functions.createEmptyAuthUser; | ||
|
||
export const FirebaseAuthMenuButton = firebaseAuthMenuButtonModule; | ||
export const FirebaseAuthUI = firebaseAuthUIModule; | ||
export const FirebaseLoginForm = firebaseLogimFormModule; | ||
export const FirebaseSignupForm = firebaseSignupFormModule; | ||
export const FirebaseUserInfo = firebaseUserInfoModule; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const FB_APP_NAME = '[DEFAULT]'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import { init, useAuthUser, withAuthUser, withAuthUserSSR, withAuthUserTokenSSR} from 'next-firebase-auth' | ||
|
||
const initAuthHelper = (function(){ | ||
let initAuthResult = {success: false, error: new Error('Firebase auth is not yet initialised')}; | ||
const getInitAuthResult = () => { | ||
return initAuthResult; | ||
} | ||
const setInitAuthResult = ({success,error}) => { | ||
initAuthResult = {success,error}; | ||
} | ||
return {getInitAuthResult, setInitAuthResult}; | ||
})(); | ||
|
||
export const getInitAuthResult = initAuthHelper.getInitAuthResult; | ||
|
||
export const createEmptyAuthUser = () => { | ||
return { | ||
id: null, | ||
email: null, | ||
emailVerified: false, | ||
phoneNumber: null, | ||
displayName: null, | ||
photoURL: null, | ||
claims: {}, | ||
getIdToken: async () => null, | ||
clientInitialized: false, | ||
firebaseUser: null, | ||
signOut: async () => null, | ||
serialize: ({ includeToken = true } = {}) => | ||
JSON.stringify({ | ||
id: null, | ||
claims: {}, | ||
email: null, | ||
emailVerified: false, | ||
phoneNumber: null, | ||
displayName: null, | ||
photoURL: null, | ||
clientInitialized: false, | ||
...(includeToken && { _token: null }), | ||
}), | ||
} | ||
} | ||
|
||
export const initAuth = () => { | ||
try { | ||
init({ | ||
loginAPIEndpoint: '/api/fb/login', // required | ||
logoutAPIEndpoint: '/api/fb/logout', // required | ||
onLoginRequestError: (err) => { | ||
console.error(err) | ||
}, | ||
onLogoutRequestError: (err) => { | ||
console.error(err) | ||
}, | ||
firebaseAdminInitConfig: { | ||
credential: { | ||
projectId: process.env.FIREBASE_PROJECT_ID, | ||
clientEmail: process.env.FIREBASE_CLIENT_EMAIL, | ||
// The private key must not be accessible on the client side. | ||
privateKey: process.env.FIREBASE_PRIVATE_KEY, | ||
}, | ||
databaseURL: process.env.FIREBASE_DATABASE_URL, | ||
}, | ||
|
||
firebaseClientInitConfig: { | ||
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, // required | ||
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, | ||
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL, | ||
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, | ||
}, | ||
cookies: { | ||
name: 'RC4Community', // required | ||
// Keys are required unless you set `signed` to `false`. | ||
// The keys cannot be accessible on the client side. | ||
keys: [ | ||
process.env.COOKIE_SECRET_CURRENT, | ||
process.env.COOKIE_SECRET_PREVIOUS, | ||
], | ||
httpOnly: true, | ||
maxAge: 12 * 60 * 60 * 24 * 1000, // twelve days | ||
overwrite: true, | ||
path: '/', | ||
sameSite: 'strict', | ||
secure: true, // set this to false in local (non-HTTPS) development | ||
signed: true, | ||
}, | ||
onVerifyTokenError: (err) => { | ||
console.error(err) | ||
}, | ||
onTokenRefreshError: (err) => { | ||
console.error(err) | ||
}, | ||
}); | ||
initAuthHelper.setInitAuthResult({error: null, success: true}); | ||
} catch (e) { | ||
console.error(e) | ||
initAuthHelper.setInitAuthResult({error: e, success: false}); | ||
} | ||
return initAuthHelper.getInitAuthResult(); | ||
} | ||
|
||
export const withFirebaseAuthUser = (options) => (ChildComponent) => { | ||
const WithFirebaseAuthUserHOC = props => { | ||
if(initAuthHelper.getInitAuthResult().success){ | ||
const Component = withAuthUser(options)(ChildComponent); | ||
return <Component {...props}/> | ||
} else { | ||
console.error(initAuthHelper.getInitAuthResult().error); | ||
console.error("You must configure firebase auth before using firebase auth. See https://github.com/RocketChat/RC4Community/blob/firebase-auth/app/components/auth/firebase/README.md"); | ||
return <ChildComponent {...props} initAuthResult={initAuthHelper.getInitAuthResult()}/> | ||
} | ||
} | ||
WithFirebaseAuthUserHOC.displayName = "WithFirebaseAuthUserHOC"; | ||
return WithFirebaseAuthUserHOC; | ||
} | ||
|
||
export const useFirebaseAuthUser = () => { | ||
if(initAuthHelper.getInitAuthResult().success){ | ||
return useAuthUser(); | ||
} else { | ||
return createEmptyAuthUser(); | ||
} | ||
} | ||
|
||
const handleFBNotInitError = async (context,getServerSidePropsFunc) => { | ||
console.error(initAuthHelper.getInitAuthResult().error); | ||
console.error("You must configure firebase auth before using firebase auth. See https://github.com/RocketChat/RC4Community/blob/firebase-auth/app/components/auth/firebase/README.md"); | ||
|
||
const AuthUser = createEmptyAuthUser(); | ||
context.AuthUser = AuthUser; | ||
|
||
const AuthUserSerialized = AuthUser.serialize(); | ||
let returnData = {props: {AuthUserSerialized}}; | ||
|
||
if(getServerSidePropsFunc) { | ||
// a getServerSideProps function is passed | ||
const composedProps = (await getServerSidePropsFunc(context)) || {}; | ||
if(composedProps){ | ||
if(composedProps.props){ | ||
returnData = { ...composedProps } | ||
returnData.props.AuthUserSerialized = AuthUserSerialized | ||
} else if(composedProps.notFound || composedProps.redirect) { | ||
// If composedProps returned a 'notFound' or 'redirect' key | ||
// (as per official doc: https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props) | ||
// it means it contains a custom dynamic routing logic that should not be overwritten | ||
returnData = {...composedProps} | ||
} | ||
} | ||
} | ||
return returnData; | ||
} | ||
|
||
export const withFirebaseAuthUserSSR = (options) => (getServerSidePropsFunc) => async (context) => { | ||
if(initAuthHelper.getInitAuthResult().success){ | ||
return withAuthUserSSR(options)(getServerSidePropsFunc)(context); | ||
} else { | ||
// firebase is uninitialised due to some error | ||
return (await handleFBNotInitError(context,getServerSidePropsFunc)); | ||
} | ||
} | ||
|
||
export const withFirebaseAuthUserTokenSSR = (options) => (getServerSidePropsFunc) => async (context) => { | ||
if(initAuthHelper.getInitAuthResult().success){ | ||
return withAuthUserTokenSSR(options)(getServerSidePropsFunc)(context); | ||
} else { | ||
// firebase is uninitialised due to some error | ||
return (await handleFBNotInitError(context,getServerSidePropsFunc)); | ||
} | ||
} | ||
|
||
export default { | ||
getInitAuthResult, | ||
createEmptyAuthUser, | ||
initAuth, | ||
useFirebaseAuthUser, | ||
withFirebaseAuthUser, | ||
withFirebaseAuthUserSSR, | ||
withFirebaseAuthUserTokenSSR | ||
}; |
45 changes: 45 additions & 0 deletions
45
app/components/auth/firebase/styles/FirebaseAuthMenuButton.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
.authDialogWrapper { | ||
position: relative; | ||
} | ||
.authContainer { | ||
display: block; | ||
position: absolute; | ||
right: 8px; | ||
top: 62px; | ||
width: 354px; | ||
max-height: -webkit-calc(100vh - 62px - 100px); | ||
max-height: calc(100vh - 62px - 100px); | ||
overflow-y: auto; | ||
overflow-x: hidden; | ||
border-radius: 8px; | ||
margin-left: 12px; | ||
z-index: 991; | ||
line-height: normal; | ||
background: #fff; | ||
border: 1px solid #ccc; | ||
border-color: rgba(0,0,0,.2); | ||
color: #000; | ||
-webkit-box-shadow: 0 2px 10px rgb(0 0 0 / 20%); | ||
box-shadow: 0 2px 10px rgb(0 0 0 / 20%); | ||
-webkit-user-select: text; | ||
user-select: text; | ||
} | ||
|
||
.avatar { | ||
background: var(--bs-gray-300); | ||
border-radius: 50%; | ||
width: 42px; | ||
height: 42px; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
|
||
.avatarButton { | ||
background: none; | ||
border: none; | ||
} | ||
|
||
.avatarButton:focus { | ||
outline: none; | ||
} |
7 changes: 7 additions & 0 deletions
7
app/components/auth/firebase/styles/FirebaseAuthUI.module.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.authUIWrapper { | ||
width: 100%; | ||
max-width: 400px; | ||
border: 1px solid #ddd; | ||
box-shadow: 2px 2px 3px 3px #0000001D; | ||
background: #FFF; | ||
} |
Oops, something went wrong.