I know this question has been asked in other contexts. I've read those answers. I've tried the answers. I've read through the firebase docs. So, far it's not helping. I'm new to firebase. Learning how to use the product by going through a tutorial on using React and Firebase together. Building an authentication/authorization module for users. Can successfully register/SignUp a user and see the results in both the authorization module and the realtime database in the firebase project overview. When the user Signs Out, a check of the RDb confirms that all the data properties persist. When the user Signs In (email/password) again, a check of the RDb shows that only the uid and the email address persist in the RDb. The non-auth properties of the user like username and role become empty strings or objects, present but not populated. I have done considerable reading of the firebase docs and debugging of the code, but I cannot determine why this happens and therefore cannot determine how to fix it.
Here are some code segments:
First the firebase module:
import app from 'firebase/app'
import 'firebase/auth'
import 'firebase/database'
... set up the config ...
// set the config constant to the appropriate value
const config = process.env.NODE_ENV === 'production' ? prodConfig : devConfig
class Firebase {
constructor() {
// initialize the app using the Firebase config to instatiate all of the firebase services
app.initializeApp(config)
// instantiate the initial auth state within the app
this.auth = app.auth() // Gets the Auth service for the current app
// instantiate the database within the app
this.db = app.database() // Gets the Database service for the current app
console.log('this.db ', this.db)
// Social media login providers (authorization methods within Firebase)
this.googleProvider = new app.auth.GoogleAuthProvider()
this.facebookProvider = new app.auth.FacebookAuthProvider()
this.twitterProvider = new app.auth.TwitterAuthProvider()
}
... the comments are mostly for my benefit ...
// ***** Firebase Auth API *****
// create user with email and password (equate doCreate... with Firebase createUser...)
doCreateUserWithEmailAndPassword = ( email, password ) => this.auth.createUserWithEmailAndPassword( email, password )
// ***** SignIn with email ***** (equate doSignIn... with Firebase signIn...)
doSignInWithEmailAndPassword = ( email, password ) => this.auth.signInWithEmailAndPassword( email, password )
// ***** SignIn with facebook ***** (equate as above)
doSignInWithFacebook = () => this.auth.signInWithPopup( this.facebookProvider )
// ***** SignIn with google ***** (equate as above)
doSignInWithGoogle = () => this.auth.signInWithPopup( this.googleProvider )
// ***** SignIn with twitter ***** (equate as above)
doSignInWithTwitter = () => this.auth.signInWithPopup( this.twitterProvider )
// ***** SignOut ***** (equate as above)
doSignOut = () => this.auth.signOut()
// ***** Password Reset ***** (equate as above)
doPasswordReset = email => this.auth.sendPasswordResetEmail( email )
// ***** Password Update ***** (equate as above)
doPasswordUpdate = password => this.auth.currentUser.updatePassword( password )
// ***** User API *****
// set the current user id
user = uid => this.db.ref(`users/${uid}`)
// set the reference to the users collection in the firebase database
users = () =>this.db.ref('users')
// ***** Merge Auth and DB User API *****
... big block of comments to me ...
onAuthUserListener = (next, fallback) =>
this.auth.onAuthStateChanged(authUser => {
if ( authUser ) {
this.user(authUser.uid)
.once('value')
.then(snapshot => {
const dbUser = snapshot.val()
console.log('this.user ',this.user)
console.log('dbUser ',dbUser)
// default empty roles
if ( !dbUser.roles ) {
dbUser.roles = {}
}
// merge auth and db user
this.db.ref(`users/${this.user}`).set({
uid: authUser.uid,
email: authUser.email,
username: authUser.username,
roles: authUser.roles,
...dbUser,
})
console.log('firebase.js authUser ', authUser)
next(authUser)
})
} else { // there is no authUser
fallback()
}
})
}
export default Firebase
Here is the Sign UP component:
// index.js - SignUp
// the entry point for the SignUp component
import React, { Component } from 'react'
import { Link, withRouter } from 'react-router-dom'
import { compose } from 'recompose'
import { Typography, Input, Checkbox, FormLabel, Button } from '@material-ui/core'
import { withFirebase } from '../Firebase'
import * as ROUTES from '../../constants/routes'
import * as ROLES from '../../constants/roles'
import '../../styles/auth.css'
const SignUpPage = () => (
<div id='wrapper' className='signup-page'>
<SignUpForm />
</div>
)
// initialize the state of the component using destructuring
// allows INITIAL_STATE to be reset after successful SignUp
const INITIAL_STATE = {
username: '',
email: '',
passwordOne: '',
passwordTwo: '',
isAdmin: false,
error: null,
}
class SignUpFormBase extends Component {
constructor(props) {
super(props)
// spread operator (...) spreads out to reach all properties individually
this.state = { ...INITIAL_STATE }
}
onSubmit = event => {
// get necessary info from this.state to pass to the Firebase authentication API
const { username, email, passwordOne, isAdmin } = this.state
const roles = {}
if ( isAdmin ) { roles[ROLES.ADMIN] = ROLES.ADMIN } // set roles if the admin checkbox is checked
this.props.firebase
// create a user (limited access) in the authentication database
.doCreateUserWithEmailAndPassword( email, passwordOne )
// successful
.then( authUser => {
// create a user in Firebase realtime database -- this is where you manage user properties
// because in the firebase auth module, users cannot be manipulated.
console.log('signup authUser ',authUser)
return this.props.firebase
.user(authUser.user.uid) // use the authUser.uid to:
.set({ username, email, roles }) // write username, email & roles to the rdb
})
.then(() => {
// update state and redirect to Home page
this.setState({ ...INITIAL_STATE })
this.props.history.push(ROUTES.HOME)
})
// error - setState, error (if something is wrong)
.catch(error => {
this.setState({ error })
})
// prevent default behavior (a reload of the browser)
event.preventDefault()
}
onChange = event => {
// dynamically set state properties when they change, based on which input call is executed
// each <input> element (in the return) operates on a different property of state (according to value)
this.setState({ [event.target.name]: event.target.value })
}
onChangeCheckbox = event => {
this.setState({ [event.target.name]: event.target.checked })
}
render() {
// parse each of the values from current state
const {
username,
email,
passwordOne,
passwordTwo,
isAdmin,
error
} = this.state
// list of invalid conditions for which to check (validation of form elements)
const isInvalid =
passwordOne !== passwordTwo ||
passwordOne === '' ||
email === '' ||
username === ''
return (
// the input form -- with fields (username, email, passwordOne, passwordTwo)
<div className='container'>
<Typography
variant='h6'
align = 'center'
className='item'
>
Sign Up Page
</Typography>
<br />
<form className='signup-form item' onSubmit={ this.onSubmit }>
<Input
className='item'
name='username'
value={username}
onChange={this.onChange}
type='text'
placeholder='Full Name'
/>
... input email, password, confirm password, checkbox to designate Admin ...
<Button
variant='contained'
className='item btn btn-secondary'
disabled={ isInvalid }
type='submit'
>
Sign Up
</Button>
{/* if there is an error (a default Firebase property), render the error message */}
{error && <p>{ error.message }</p>}
</form>
</div>
)
}
}
const SignUpLink = () => (
<Typography
variant = 'body1'
align = 'center'
className = 'item'
>
Don't have an account? <Link to={ ROUTES.SIGN_UP }>Sign Up</Link>
</Typography>
)
const SignUpForm = compose(withRouter, withFirebase)(SignUpFormBase)
export default SignUpPage
export { SignUpForm, SignUpLink }
Here is the Sign IN (email/password) component:
// SignInEmail.js - SignIn
// the email/password SignIn component
import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
import { compose } from 'recompose'
import { Typography, Input } from '@material-ui/core'
import Button from 'react-bootstrap/Button'
import { withFirebase } from '../Firebase'
import * as ROUTES from '../../constants/routes'
// initialize the state of the component using destructuring
// allows INITIAL_STATE to be reset after successful SignUp
const INITIAL_STATE = {
username: '',
email: '',
password: '',
roles: {},
error: null,
}
// ======================================
// ***** signin with email/password *****
// ======================================
class SignInEmailBase extends Component {
constructor(props) {
super(props)
// spread operator (...) spreads out to reach all properties individually
this.state = {
...INITIAL_STATE
}
}
onSubmit = event => {
// get necessary info from this.state to pass to the Firebase authentication API
// const { username, email, password, roles } = this.state
const { username, email, password, roles } = this.state
this.props.firebase
// execute SignIn function (create a user)
.doSignInWithEmailAndPassword( email, password )
// successful
.then(authUser => {
// create a user in Firebase Realtime database
console.log('signin authUser ',authUser)
return this.props.firebase
.user(authUser.user.uid)
.set({ username, email, roles })
})
.then(() => {
// update state and redirect to Home page
this.setState({ ...INITIAL_STATE })
this.props.history.push(ROUTES.HOME)
})
// error - setState, error (if something is wrong)
.catch(error => {
this.setState({
error
})
})
// prevent default behavior (a reload of the browser)
event.preventDefault()
}
onChange = event => {
// dynamically set state properties when they change, based on which input call is executed
// each <input> element (in the return) operates on a different property of state (according to value)
this.setState({ [event.target.name]: event.target.value })
}
render() {
// parse each of the values from current state
const { email, password, error } = this.state
// list of invalid conditions for which to check (validation of form elements)
const isInvalid = password === '' || email === ''
return (
// the input form -- with fields (username, email, passwordOne, passwordTwo)
<div className = 'container signin-page'>
<Typography
variant = 'h6'
align = 'center'
className = 'item'
>
Sign In Page
</Typography>
<br />
<form className = 'item email-form' onSubmit = { this.onSubmit} >
... input email, password...
{ /* disable the button if the form is invalid -- see isInvalid above */ }
<Button
className = 'item btn btn-secondary'
type = 'submit'
disabled = { isInvalid }
>
SIGN IN WITH EMAIL
</Button>
{ /* if there is an error (a default Firebase property), render the error message */ }
{ error && <p> { error.message } </p> }
</form>
</div>
)
}
}
const SignInEmail = compose(withRouter, withFirebase, )(SignInEmailBase)
export default SignInEmail
Here is the screenshot of the browser inspect and the screenshot of the Realtime Database entry after Sign UP

Here is the same user after sign out and sign in -- no other data manipulation
I sure could use some help. Thanks.


