I have a react app and I have added firebase to it. The Sign Up creates a new user account but since the user has to be tracked I have gotten the user's id token and added it to local storage. It then takes the user to a dashboard page with the route link "/dashboard" but anyone can go to that link without signing up, it takes the id token kept in local storage, it then uses firebase admin to verify the id. If the verification is a success, it loads the page. Else it redirects the user to the login page. However when I created a new account, I got directed to the dashboard, and then redirected back to the login page. The id token had been correctly put into the local storage and the account had been created, but I got the error Failed to determine project ID: Error while making request: Failed to fetch. Error code: undefined at FirebaseAppError.FirebaseError [as constructor] (error.js:44) at FirebaseAppError.PrefixedFirebaseError [as constructor] (error.js:90) at new FirebaseAppError (error.js:125) at credential-internal.js:183.Here is my code:
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import firebase from "firebase/app";
import admin from "firebase-admin";
const firebaseConfig = {
// In the actual code I have set all of them
}
firebase.initializeApp(firebaseConfig);
admin.initializeApp();
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
Signup.js:
import React, { useState, useEffect } from "react";
import { useHistory, Link } from "react-router-dom";
import firebase from "firebase";
import admin from "firebase-admin";
function Signup() {
const [userInfo, setUserInfo] = useState({email: "", username: "", password: ""});
const [errorMessage, setErrorMessage] = useState();
const [idToken, setIdToken] = useState();
const history = useHistory();
useEffect(() => {
setIdToken(localStorage.getItem("idToken"));
if (idToken !== undefined && idToken !== null) {
admin.auth().verifyIdToken(idToken)
.then(() => {
history.push("/dashboard");
})
.catch(() => {
localStorage.removeItem("idToken");
})
}
}, []);
const getText = ({target}) => {
setUserInfo({...userInfo, [target.name]: target.value});
}
const signup = (e) => {
e.preventDefault();
const {username, email, password} = userInfo;
if (username === "" || email === "" || password === "") {
setErrorMessage("Username, Email and Password cannot be empty.");
} else if (password.length < 8) {
setErrorMessage("Password cannot be less than 8 characters long.");
} else {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then((userCredential) => {
userCredential.user.updateProfile({
displayName: username
})
userCredential.user.getIdToken()
.then((idToken) => {
localStorage.setItem("idToken", idToken);
history.push("/dashboard");
})
})
.catch((error) => {
setErrorMessage(error.message);
})
}
}
return(
<div>
<form onSubmit={signup}>
<input
type="email"
name="email"
placeholder="Email"
onChange={getText}
/>
<br />
<input
type="text"
name="username"
placeholder="Username"
onChange={getText}
/>
<br />
<input
type="password"
name="password"
placeholder="Password"
onChange={getText}
/>
<br />
<p>{errorMessage}</p>
<input type="submit" value="Sign Up" />
<p>Already have an account? <Link to="/login">Log In</Link></p>
</form>
</div>
);
}
export default Signup;
Dashboard.js:
import React, { useEffect } from "react";
import { useHistory } from "react-router-dom";
import admin from "firebase-admin";
function Dashboard() {
const history = useHistory();
useEffect(() => {
const idToken = localStorage.getItem("idToken");
if (idToken !== undefined && idToken !== null) {
admin.auth().verifyIdToken(idToken)
.catch((error) => {
console.log(error);
localStorage.removeItem("idToken");
history.push("/login");
})
} else {
localStorage.removeItem("idToken");
history.push("/login");
}
}, []);
return <h1>Dashboard</h1>
}
export default Dashboard;
Firebase-admin example initialization (it's different from firebase client side)
let admin = require('firebase-admin')
let serviceAccount = require('./theserviceaccountfile.json');
let db
module.exports = async function() {
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://project-id.firebaseio.com",
})
if (!db) {
db = admin.database()
}
}
return db
}
Related
So, I'm able to create an account and to successfully get to the MyAccount page, see who's currently logged in to MyAccount page and log out of the MyAccount page (MyAccount.js).
However, when I try to log in using an email + password by pressing the Sign In button of the Body2.js, I can reach the MyAccount page but can't see who's logged in and I get the "User already Logged In!" error message.
Here's my firebase file:
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { createUserWithEmailAndPassword, getAuth, onAuthStateChanged, signOut, signInWithEmailAndPassword } from "firebase/auth";
import { useEffect, useState } from "react";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
projectId: "XXXXXXXXXXXXXXXXX",
storageBucket: "XXXXXXXXXXXXXXXXXXXXXXXXX",
messagingSenderId: "XXXXXXXXXXXXXXXXXXXXXXXX",
appId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
measurementId: "XXXXXXXXXXXXXXXXXXXXXXXXXX"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
export function signup(email, password) {
return createUserWithEmailAndPassword(auth, email, password);
}
export function logout() {
return signOut(auth);
}
export function login(email, password) {
return signInWithEmailAndPassword(auth, email, password);
}
// Custom Hook
export function useAuth() {
const [ currentUser, setCurrentUser ] = useState();
useEffect(() => {
const unsub = onAuthStateChanged(auth, user => setCurrentUser(user));
return unsub;
}, [])
return currentUser;
}
Here's my App.js file:
import React, { useState } from 'react';
import './App.css';
import Header from './Header';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Menu from './Menu';
import HeaderBlock from './HeaderBlock';
import Header2 from './Header2';
import Body2 from './Body2';
import Footer2 from './Footer2';
import SignUp from './SignUp';
import MyAccount from './MyAccount' ;
function App() {
const [isMenuOpen, setIsMenuOpen] = useState(false);
return (
<Router>
<div className="app">
<Switch>
<Route exact path='/'>
<Header isMenuOpen={isMenuOpen} setIsMenuOpen={setIsMenuOpen}/>
{isMenuOpen && <Menu/>}
<HeaderBlock />
</Route>
<Route exact path='/Login2'>
<Header2 />
<Body2 />
<Footer2 />
</Route>
<Route exact path='/signup'>
<Header2 />
<SignUp />
<Footer2 />
</Route>
<Route exact path='/MyAccount'>
<Header2 />
<MyAccount />
<Footer2 />
</Route>
</Switch>
</div>
</Router>
);
}
export default App;
Here's my signup file:
import './SignUp.css';
import React, { useState, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import { signup, useAuth } from './firebase';
function SignUp() {
const history = useHistory();
const emailRef = useRef();
const passwordRef = useRef();
const [ loading, setLoading ] = useState(false);
const currentUser = useAuth();
async function handleSignup() {
setLoading(true);
try {
await signup(emailRef.current.value, passwordRef.current.value);
}
catch {
alert("Account already created/Credentials already used");
}
setLoading(false);
};
return (
<div className='signup'>
<div className='signup__info'>
<h1> Account Creation </h1>
<form className='signup__form'>
<label htmlFor='email'> Email Address </label>
<input
ref={emailRef}
placeholder=''
/>
<label htmlFor='email'> Password </label>
<input
ref={passwordRef}
type="password"
placeholder=""
/>
<div className='signupblock__actions'>
<button
className='signupblock__buttonPrimary'
disabled={ loading || currentUser }
onClick={() => {handleSignup(); history.push('/MyAccount');}}> Register </button>
<div className='signupblock__divider'>
<hr/> <span> OR </span> <hr/>
</div>
<button
className='signupblock__buttonSecondary'
onClick={() => {history.push('/');}}> Home </button>
</div>
</form>
</div>
</div>
);
};
export default SignUp;
Here's my Body2.js file:
import React, { useState, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import './Body2.css';
import { useAuth, login } from './firebase';
function Body2() {
const history = useHistory()
const currentUser = useAuth();
const [ loading, setLoading ] = useState(false);
const emailRef = useRef();
const passwordRef = useRef();
async function handleLogin() {
setLoading(true);
try {
await login(emailRef.current.value, passwordRef.current.value);
}
catch {
alert("User already Logged In!");
}
setLoading(false);
};
return (
<div className='body2'>
<div className='login2__info'>
<h1> Sign In </h1>
<form className='login2__form'>
<label htmlFor='email'> Email Address </label>
<input
type='email'
id='email'
/>
<label htmlFor='email'> Password </label>
<input
type='password'
id='password'
/>
<div className='headerBlock2__actions'>
<button
className='headerBlock2__buttonPrimary'
disabled={ loading || currentUser }
onClick={() => {handleLogin(); history.push('/MyAccount');}} > Sign In </button>
<div className='login2__divider'>
<hr/> <span> OR </span> <hr/>
</div>
<button
className='headerBlock2__buttonSecondary'
onClick={() => {history.push('/signup');}}> Create Account </button>
</div>
</form>
</div>
</div>
)
}
export default Body2;
Here's my Account.js file:
import React, { useState } from 'react';
// import app from './firebase';
import './MyAccount.css';
import { logout, useAuth } from './firebase';
import { useHistory } from 'react-router-dom';
function Home() {
const history = useHistory();
const currentUser = useAuth();
const [ loading, setLoading ] = useState(false);
async function handleLogOut() {
setLoading(true);
try {
await logout();
}
catch {
alert("Couldn't Log Out Effectively");
}
setLoading(false);
}
return (
<div>
<h1> Home </h1>
<p> What's Up Everyone! </p>
<h2> Currently logged in as: { currentUser?.email } </h2>
<button
disabled={ loading }
onClick={() => {handleLogOut(); history.push('/');}}> Log Out </button>
</div>
);
}
export default Home;
I think I'm not resetting the current user value in Body2.js but I'm not sure or don't know how to.
I am following a tutorial on how to integrate Stripe payments in React. The problem I am having is for this page where it will check if a user is logged in and if they are logged in it will show a cookie and if they are not it will show a upgrade to premium button. All is working however there is an annoying behaviour where if I refresh the page it briefly shows the 'Upgrade to premium' button before checking the user is premium and then quickly change to the cookie. I want it to ideally do the check before the content is rendered so it's a bit smoother and doesn't look jittery.
import React, { useEffect,useState } from 'react'
import firebase from "../src/firebase";
import { useAuthState } from "react-firebase-hooks/auth";
import { getAuth, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut,onAuthStateChanged } from "firebase/auth";
import createCheckoutSession from "./stripe/createCheckoutSession";
import usePremiumStatus from "./stripe/usePremiumStatus";
import Login from "./Login";
import { Link, useNavigate } from 'react-router-dom'
import { Spinner } from 'react-bootstrap';
export default function Practise() {
const auth = getAuth();
const {currentUser}=getAuth()
const userIsPremium = usePremiumStatus(currentUser);
const [load,setLoading]=useState(false)
const debugging = async ()=>{
const {currentUser}= await getAuth().then(()=>{
console.log(currentUser)
})
}
const [loggedIn,setLoggedIn]= useState(false)
let navigate = useNavigate();
const handleNewInfo = ()=>{
onAuthStateChanged(auth, (user) => {
if (user) {
const uid = user.uid;
setLoggedIn(true)
const prom = async ()=>{
await ((user.getIdTokenResult()))
}
prom()
console.log(userIsPremium)
} else {
navigate('/login')
console.log('not logged in!')
}
})}
const getUser = ()=>{
console.log(currentUser)
}
useEffect(
handleNewInfo
,[]
) ;
const handleClick = (userid)=>{
setLoading(true)
createCheckoutSession(userid)
}
return (
<div>
{!loggedIn && <h1>Loading...</h1>}
{loggedIn && (
<div>
<h1>Hello, {currentUser.displayName}</h1>
{!userIsPremium && (
<button onClick={() => handleClick(currentUser.uid)}>
Upgrade to premium!
</button>
) }
{!userIsPremium && load && (
<Spinner animation="border" role="status">
<span className="visually-hidden">Loading...</span>
</Spinner>
) }
{userIsPremium && <h2>Have a cookie 🍪 Premium customer!</h2>
}
</div>
)}
</div>
);
}
I am using firebase authentication in my react application for sign-in users but when i entered my email which is 'namangarg82#gmail.com' and Click on Sign in button it shows an error:- Cannot create property '_canInitEmulator' on string 'namangarg82#gmail.com'
My Signup.js file
import React, { useContext, useRef,useState} from 'react'
import { Form, Button, Card,Alert } from 'react-bootstrap'
import { useAuth } from './AuthContext';
import { AuthProvider } from './AuthContext';
export function Signup() {
const emailRef=useRef();
const passwordRef=useRef();
const passwordConfirmRef=useRef();
const { signup } =useAuth()
const [error,setError]=useState('')
const [loading,setLoading]=useState(false)
console.log(error,"12",loading);
console.log(useAuth(),"ji")
// const{a}=useContext(AuthProvider);
// console.log(a);
async function handleSubmit(e){
e.preventDefault()
if(passwordRef.current.value!==passwordConfirmRef.current.value)
{
console.log(passwordRef.current.value);
return setError("Passwords do not match")
}
try{
console.log("try");
setLoading(true);
setError("");
console.log(emailRef.current.value,passwordRef.current.value);
await signup(emailRef.current.value,passwordRef.current.value)
} catch(err){
console.log("hi",err);
setError("Failed to create an account")
}
setLoading(false);
console.log(loading,"8");
}
return (
<div>
<Card>
<Card.Body className="text-center mb-4">
<h2>SignUp</h2>
{error && <Alert variant="danger">{error}</Alert>}
<Form onSubmit={(e)=>{handleSubmit(e)} }>
<Form.Group id="email">
<Form.Label>Email</Form.Label>
<Form.Control type="email" ref={emailRef}>
</Form.Control>
</Form.Group>
<Form.Group id="password">
<Form.Label>Password</Form.Label>
<Form.Control type="password" ref={passwordRef}>
</Form.Control>
</Form.Group>
<Form.Group id="passwordConfirm">
<Form.Label>Password Confirmation</Form.Label>
<Form.Control type="password" ref={passwordConfirmRef}>
</Form.Control>
</Form.Group>
<Button disabled={loading} type="submit" className="w-100">Sign Up</Button>
</Form>
</Card.Body>
</Card>
</div>
)
}
export default Signup
My Authcontext file
import React,{createContext,useContext,useState,useEffect} from 'react'
import {auth} from '../Firebase'
import { createUserWithEmailAndPassword} from "firebase/auth";
// const AuthContext =React.createContext()
const AuthContext =createContext()
export function useAuth(){
return useContext(AuthContext)
}
export function AuthProvider({children}) {
const [currentUser,setCurrentUser]=useState()
function signup(email,password){
return createUserWithEmailAndPassword(email,password)
}
useEffect(() => {
const unsuscribe = auth.onAuthStateChanged(user=>{
setCurrentUser(user)
})
return unsuscribe
}, [])
const value={
currentUser,
signup,
}
return (
<div>
< AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
</div>
)
}
export default AuthContext
and my firebase setup is
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
apiKey: "AIzaSyDLlZn08b5PlDpiqTQNxkyfpOPpz_6Gh8o",
authDomain: "portfolio-279ef.firebaseapp.com",
projectId: "portfolio-279ef",
storageBucket: "portfolio-279ef.appspot.com",
messagingSenderId: "778898179742",
appId: "1:778898179742:web:7beb09bf995e5041de1d8f"
};
const Firebaseapp = initializeApp(firebaseConfig);
export const auth=getAuth();
export default Firebaseapp;
Please help me
With new firebase functional approach, you need to include auth parameter like this:
createUserWithEmailAndPassword(auth, email, password)
In the firebase 9.0^, you try with this, in almost all methods, the auth method is inserted first, and import from your firebase setup.
//With your app initialized
import {getAuth} from 'firebase/auth'
...
const auth = getAuth()
return createUserWithEmailAndPassword(auth, email,password)
Source: https://firebase.google.com/docs/auth/web/password-auth?hl=pt
In your AuthContext file, createUserWithEmailAndPassword must include auth too:
createUserWithEmailAndPassword(auth, email, password)
I have built a simple app with Nextjs and Firebase (right now, I'm only using the authentication providing by Firebase). I made a login component and a greetingUser component whose roles are defined as follow :
greetingUser : display the name of the user currently logged in and a greeting message;
// greetingUse.js
import React, { useContext } from 'react';
import { UserContext } from './User/User';
export default function GreetUser(){
const user = useContext(UserContext);
return (
<div>
<p>hello, {user.user.name} !</p>
</div>
)
}
login : there are two buttons (login and logout). When the user log in, I want to receive the name of the user (user.displayName) and update the greetingUser component to display that name.
// login.js
import firebase from 'firebase/app';
import React, { useContext, useReducer } from 'react';
import { UserContext } from './User/User';
import { auth } from '../utils/firebase';
export default function Login() {
const provider = new firebase.auth.GoogleAuthProvider();
const state = useContext(UserContext);
console.log(state);
console.log(state.user);
const updateUserDetails = () => {
auth.onAuthStateChanged(user => {
if (user) {
return user.displayName;
} else {
return "You are logged out";
}
})
console.log(state.user);
}
return (
<>
<div className="btn-group">
<button
id="logInBtn"
className="btn btn-primary"
onClick={() => auth.signInWithPopup(provider) && state.setUser(updateUserDetails())}>
Login
</button>
<button
id="logOutBtn"
className="btn btn-danger"
onClick={() => auth.signOut()}>
Logout
</button>
</div>
<p>hello {state.user.name}</p>
</>
)
}
You'll notice that I'm using react context. After some research, that the solution I found. Here is the Provider code :
// User.js
import React, { createContext, useState } from 'react';
const UserContext = createContext({
user: {name: "User"},
setUser: () => {}
});
const UserContextProvider = (props) => {
const setUser = (user) => {
setState({...state, user: user})
}
const initState = {
user: {name: "User"},
setUser: setUser
}
const [state, setState] = useState(initState);
return (
<UserContext.Provider value={state}>
{props.children}
</UserContext.Provider>
)
};
export { UserContext, UserContextProvider };
The problem is when logging in, the value of the user object is undefined resulting in an error that prevent the page from rendering :
login.js?4f9b:42 Uncaught TypeError: Cannot read property 'name' of undefined at Login (login.js?4f9b:42)
I thing it's because while authenticating, the value of user is unknow, but after the authentification is completed, the value of user is not updated.
I did some research, but I don't find a solution adapted to my problem.
I am trying to route the user to specific route according to user's role. I am using redux as state management tool. I am trying to access the user object from auth state to route the user.
When I login to the system below are the logical steps that take user to route.
Login to the system
Authenticate and load the user
Redirect user to route according to role
I am trying to access the user.role in DashBoard component which is causing the error.
Please help me understand the bug.
1. Action to login to system
export const login = (email, password) => async dispatch => {
const config ={
headers:{
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({email, password});
try {
const res = await axios.post('/api/v1/midasUsers/login',body,config);
dispatch({
type:LOGIN_SUCCESS,
payload:res.data
});
dispatch(loadUser());
} catch (err) {
console.log(err)
const errors = err.response.data.errors;
if(errors){
errors.forEach(error =>dispatch(setAlert(error.msg,'danger')));
}
dispatch({
type:LOGIN_FAIL
})
}
}
2.loaduser to localstorage to authenticate:
export const loadUser = () => async dispatch => {
console.log("I am inside loaduser");
if(localStorage.token){
setAuthToken(localStorage.token)
}
try {
const res = await axios.get('/api/v1/midasUsers/auth');
dispatch({
type: USER_LOADED,
payload:res.data
})
} catch (err) {
dispatch({
type: AUTH_ERROR
})
}
}
3. DashBord.js - Component to route the user
import React,{useEffect} from 'react';
import {Redirect} from 'react-router-dom';
import { connect} from 'react-redux';
import PropTypes from 'prop-types';
//import store from '../../store';
//import {loadUser} from '../../action/auth';
const Dashboard = ({auth:{user,loading,isAuthenticated}}) => {
if(user.role === 'admin'){
return <Redirect to='/adminLandingPage'/>
}
}
Dashboard.propTypes = {
auth:PropTypes.object.isRequired
}
const mapStateToProps = state => ({
auth : state.auth
})
export default connect(mapStateToProps,{})(Dashboard);
I am calling loadUser everytime App.js is mounted the same function after LOGIN_SUCCESS action calls this route
GET /%3Canonymous%3E
Please help me understand the issue
auth.reducer
import {REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT} from '../action/types';
const initialState = {
token : localStorage.getItem('token'),
isAuthenticated : null,
loading: true,
user:null
}
export default function(state= initialState, action){
const {type, payload} = action;
switch (type) {
case USER_LOADED:
return{
...state,
isAuthenticated:true,
loading: false,
user:payload
}
case REGISTER_SUCCESS:
case LOGIN_SUCCESS:
localStorage.setItem('token', payload.token);
return{
...state,
...payload,
isAuthenticated:true,
loading:false,
}
case REGISTER_FAIL:
case AUTH_ERROR:
case LOGIN_FAIL:
case LOGOUT:
localStorage.removeItem('token');
return{
...state,
token:null,
isAuthenticated:false,
loading:false
}
default:
return state;
}
}
store.js
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
export default store;
index.js in reducers folder
import { combineReducers } from 'redux';
import alert from './alert';
import auth from './auth';
export default combineReducers ({
alert,
auth
});
import React, { Fragment, useState } from 'react';
import { Link, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { login } from '../../action/auth';
const Login = ({ login, isAuthenticated, user }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const { email, password } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async e => {
e.preventDefault();
login(email, password);
};
//Redirect if logged in
if(isAuthenticated){
//console.log(user.role);
return <Redirect to ="/dashboard"/>
}
return (
<Fragment>
<h1 className='large text-primary'>Sign In</h1>
<p className='lead'>
<i className='fas fa-user' /> Sign Into Your Account
</p>
<form className='form' onSubmit={e => onSubmit(e)}>
<div className='form-group'>
<input
type='email'
placeholder='Email Address'
name='email'
value={email}
onChange={e => onChange(e)}
/>
</div>
<div className='form-group'>
<input
type='password'
placeholder='Password'
name='password'
value={password}
onChange={e => onChange(e)}
minLength='6'
/>
</div>
<input type='submit' className='btn btn-primary' value='Login' />
</form>
<p className='my-1'>
Don't have an account? <Link to='/register'>Sign Up</Link>
</p>
</Fragment>
);
};
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated:PropTypes.bool
};
const mapStateToProps = state =>({
isAuthenticated : state.auth.isAuthenticated,
user:state.auth.user
})
export default connect(mapStateToProps,
{ login }
)(Login);
I have this login component which redirects user to dashbaord and at dashbaord i am not able to access the user.role from state