I am trying to figure out how to add authentication to a react app that uses Cloud Firestore rather than Realtime Database.
I followed this tutorial and got the whole thing working. Then - the change I'm trying to add is the move from Realtime Database to Cloud Firestore - this makes a difference to whether authentication works. I have made 20 new projects to try to get this work - totally without the process in the tutorial and just relying on firebase documentation. None of them work.
Currently, I have a config file with:
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import firestore from "firebase/firestore";
class Firebase {
constructor() {
app.initializeApp(config).firestore();
this.auth = app.default.auth();
// this.db = app.firebase.database()
this.db = app.firestore();
}
Then, i have a form with this submit handler:
import Firebase from '../../../firebase.1';
handleCreate = () => {
const { form } = this.formRef.props;
form.validateFields((err, values) => {
if (err) {
return;
};
const payload = {
// ...values,
name: values.name,
email: values.email,
organisation: values.organisation,
beta: values.beta,
role: values.role,
// createdAt: Firebase.FieldValue.serverTimestamp()
}
console.log("formvalues", payload);
Firebase
.auth()
.createUserWithEmailAndPassword(values.email, values.password)
console.log('Received values of form: ', values);
Firebase
.collection("users")
.add(payload)
// .then(docRef => {
// resetForm(initialValues);
// })
.then(e => this.setState({ modalShow: true }))
form.resetFields();
this.setState({ visible: false });
this.props.history.push(DASHBOARD);
});
};
At the moment, when I console.log(Firebase) I get:
Uncaught ReferenceError: Firebase is not defined
I have seen this post and followed each one of the recommendations in all of the answers.
I have tried changing the config file uses:
this.auth = app.default.auth();
It makes no difference.
When I try to use this, i get an error that says:
TypeError: _firebase_1__WEBPACK_IMPORTED_MODULE_14__.default.auth is not a function
Does anyone know how to use auth with firebase - where there is a Cloud Firestore instead of a Realtime Database - it's so weird that this makes a difference to whether the authentication tool works.
I've turned off the timestamp entry because I can't get firestore to record that either - but that is a problem for another day. I'm really trying to figure out how to use the authentication tool for now.
NEXT ATTEMPT
I tried to change the firebase.js file so that the config now looks like this:
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
const devConfig = {
};
const prodConfig = {
};
const config =
process.env.NODE_ENV === 'production' ? prodConfig : devConfig;
const Firebase = app.initializeApp(config);
const database = app.firestore();
const auth = app.auth();
const settings = { timestampsInSnapshots: true };
export { Firebase, database as default, settings, auth };
Now, I get an error that says:
TypeError: _components_firebase__WEBPACK_IMPORTED_MODULE_2__.default
is not a constructor
I have been googling - what is a constructor. What is a webpack imported module number reference etc for the last few hours. I would love to know how to translate these error messages into something understandable.
Googling this exact error message suggests that something is wrong with the way the import and export statements are made. The new export in firebase.js is unusual (but others on Stack Overflow have tried it with problems using Firebase). It's still a question mark for me because I don't understand what the error message means.
The error message points to this line of my src/index.js
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
That line comes from:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase.1';
export default Firebase;
export { FirebaseContext, withFirebase };
That file imports from:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
It would be a huge reveal if anyone has any advice for learning how to learn what error messages mean. For the moment I'm guessing.
I just finished the tutorial recently also, but I simplified my firebase file. I export only the reference to the initialised firebase
import app from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
const config = {
//...
};
const firebase = app.initializeApp(config);
export default firebase;
And in my project I have:
//...
import firebase from '../../firebase';
//...
useEffect(() => {
const listener = firebase
.firestore()
.collection(COLLECTIONS.USERS)
.onSnapshot(querySnapshot => {
setUsers(querySnapshot);
querySnapshot.forEach(doc => console.log(doc.id, doc.data()));
});
return listener;
}, []);
//...
Check out my Github project here -> https://github.com/henev/react-auth-with-firebase
Related
So basically the console is showing me that I have an unexpected token but I don't think there is any unexpected token. Please help me. I have taken way too much time trying to fix this problem. Here is the code -
import React from 'react';
import firebase from 'firebase';
export default function App() {
// I have deleted this information because I don't want anyone to access my data
const firebaseConfig = {};
firebase.initializeApp(firebaseConfig);
function signInWithGoogle() {
var google_provider = new firebase.auth.GoogleAuthProvider();
firebase
.auth()
.signInWithPopup(google_provider)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
});
}
return (
<div>
<h1>Google Sign In Authentication</h1>
<button onClick={signInWithGoogle}>Sign In</button>
</div>
);
}
The only issue I see in the provided code is you have not imported the Firebase Auth SDK. You can import that as shown below:
import firebase from 'firebase';
import "firebase/auth"
Also make sure you are using V8.X.X or lower with above code. If you have new Modular SDK V9.0.0+ then change your imports to compat version to keep using existing code:
import firebase from 'firebase/compat/app';
import "firebase/compat/auth"
I'm using firebase stripe extension "run subscriptions with stripe". In this extension integration i'm not able to redirect the checkout page (redirectToCheckout function did not work)..Any ideas how can i do that???
Here is my stripe webhooks events:
customer.subscription.updated
customer.subscription.deleted
customer.subscription.created
checkout.session.completed
price.updated
price.deleted
price.created
product.updated
product.deleted
product.created
Here is my first screen code in which user is creating...!
import firebase from 'firebase';
// import getStripe from './stripe';
import { loadStripe } from '#stripe/stripe-js/pure';
import '#stripe/stripe-js';
import redirectToCheckout from '#stripe/stripe-js';
const firestore = firebase.firestore();
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log(user.uid)
// User logged in already or has just logged in.
} else {
// User not logged in or has just logged out.
}
});
export async function createCheckoutSession(){
let uid = "static uid";
const checkoutSessionRef = await firestore.collection('stripe').doc(uid).collection('checkout_sessions').add(
{price : 'price id',
success_url : 'https://localhost:3000/success',
cancel_url: 'https://localhost:3000/fail',
});
checkoutSessionRef.onSnapshot(async (snap) => {
const {error , sessionId} = snap.data();
if (error) {
// Show an error to your customer and
// inspect your Cloud Function logs in the Firebase console.
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
const stripe = await loadStripe('pk_test_1234');
stripe.redirectToCheckout({ sessionId });
}
});
}
I am using the same code and it's working fine. The only difference I see here which might be the reason for your problem is that you are importing loadStripe from #stripe/stripe-js/pure which might need to be from "#stripe/stripe-js" and I don't think you need any other stripe import, for example, your imports should be like
import firebase from 'firebase';
import { loadStripe } from '#stripe/stripe-js';
I have these imports and they are working fine
Whenever I try to use login with facebook provided by firebase i get this error!
even tho all other popup look just fine i can't seem to know how can i fix this one?
code :
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
const config = {};
if (!firebase.apps.length) {
firebase.initializeApp(config);
}
export const auth = firebase.auth();
export const firestore = firebase.firestore();
const provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({ prompt: 'select_account' });
export const signInWithGoogle = () => auth.signInWithPopup(provider);
const fbProvider = new firebase.auth.FacebookAuthProvider();
fbProvider.setCustomParameters({ display: 'popup' });
export const signInWithFb = () => auth.signInWithPopup(fbProvider);
export default firebase;
If the popup looks fine then you don't need to fix this error. It clearly states that this message is only visible to developers at the end of the warning. Does it still appear in the production build, when deployed to the registered domain?
I am trying to follow this tutorial.
I'm currently stuck at the step which introduces react context to firebase.
This code block is the source of the current problem:
import Firebase, { FirebaseContext } from './components/firebase';
ReactDOM.render(
<FirebaseContext.Provider value={new Firebase()}>
<App />
</FirebaseContext.Provider>,
document.getElementById('root'),
);
serviceWorker.unregister();
When I try this, I get an error that says:
TypeError:_components_firebase__WEBPACK_IMPORTED_MODULE_5__.default is not a constructor
I have seen this post, which relates to Vue but says that the cause of an error with .default is not a constructor (not the rest of it), is because Firebase object should not be called with new keyword.
I tried removing new, but that generates an error message that says:
TypeError: Object(...) is not a function
I'm wondering if this has anything to do with the unusual way that the tutorial configures the app for firebase - which is with a class that uses a constructor (still don't understand why this is done this way):
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
this.db = app.database();
}
export default Firebase;
Does anyone using Firebase with React know how to use the context API and if you do, have you found a way around this problem?
The firebase config setup files are:
index:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase.1';
export default Firebase;
export { FirebaseContext, withFirebase };
context:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
NEXT ATTEMPT
I found this post, which looks like it might have been trying to follow the same tutorial.
That approach requires that I add back the auth method in the firebase.1.js config file so that it now looks like this:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
this.auth = app.auth();
// this.db = app.database();
// this.db = app.firebase.database()
this.db = app.firestore();
}
doCreateUserWithEmailAndPassword = (email, password) =>
this.auth.createUserWithEmailAndPassword(email, password);
}
Then, the submit handler in the form is like this:
handleCreate = values => {
values.preventDefault();
const { name, email, password } = this.state;
Firebase
.doCreateUserWithEmailAndPassword = (email, password) => {
return this.auth
.createUserWithEmailAndPassword(email, password)
.then((res) => {
Firebase.firestore().collection("users").doc(res.user.uid).set({
email: values.email,
name: values.name,
role: values.role,
createdAt: Firebase.FieldValue.serverTimestamp()
}).then(() => this.history.push(ROUTES.DASHBOARD));
})
.catch(err => {
console.log(err.message);
});
};
};
When I try this, I don't get any errors, but the form does not submit - it just hangs.
NEXT ATTEMPT
Since the FirebaseContext.Consumer includes a line with firebase in lowercase, I tried all of the same steps above, but replacing title case Firebase with lower case firebase. I also tried this.firebase (I don't know why) and this.props.firebase (I have seen other posts try that but still don't know why).
None of these approaches work either.
When I try to console.log(Firebase) above the FirebaseContext.Provider, I get this a big log with lots of drop down menus that starts with this:
FirebaseAppImpl {firebase_: {…}, isDeleted_: false, services_: {…},
tokenListeners_: Array(0), analyticsEventRequests_: Array(0), …}
INTERNAL: {analytics: {…}, getUid: ƒ, getToken: ƒ,
addAuthTokenListener: ƒ, removeAuthTokenListener: ƒ}
One of the drop down menus inside this log is labelled "options_" and includes my firebase app credentials.
I think this could be related to the problem in my recent other answer.
I managed to get new Firebase working by simplifying the import/export setup.
In the react app the imports are now:
import { FirebaseContext } from './components/context';
import Firebase from './components/firebase';
Those imports and the new work after I replaced the complicated "import and re-export" code in the components/firebase.js with simply the definition for the class Firebase from the tutorial.
After this another error Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app). pops up, but that could be because I didn't follow the whole tutorial and some configuration is missing.
Replicating everything you are dealing with is quite difficult without having the full source of your project.
Here is the test App.js I used after the npx create-react-app react-firebase-authentication and after installing firebase.
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { FirebaseContext } from './components/context';
import Firebase from './components/firebase';
function App() {
const foo = new Firebase()
return (
<div className="App">
... omitted ...
</div>
);
}
export default App;
I'm stuck on making firebase work in my gatsby application that uses Redux with Redux-sagas. I know about the existence of firebase-sagas but I'm trying to make without using it.
I'm trying to init firebase auth by:
import * as firebase from 'firebase/app';
import 'firebase/auth';
export const app = firebase.initializeApp(
{
apiKey : "apiKey",
authDomain : "project.firebaseapp.com",
databaseURL : "https://project.firebaseio.com",
projectId : "project",
storageBucket : "project.appspot.com",
appId : "appId"
}
)
export const authRef = () => app.auth(); //also tried: firebase.auth() and firebase.auth(app)
//firebase.auth returns a function, but firebase.auth() throws error
I have the following config on my gatsby-node.js:
const path = require('path');
exports.onCreateWebpackConfig = ({ actions, plugins, loaders, getConfig }) => {
const config = getConfig()
config.resolve = {
...config.resolve,
mainFields: ['module', 'browser', 'main'],
alias: {
...config.resolve.alias,
['firebase/app'] : path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js'),
['firebase/auth'] : path.resolve(__dirname, 'node_modules/firebase/auth/dist/index.cjs.js'),
}
}
actions.replaceWebpackConfig(config)
}
It trows the error:
{ [M [Error]: The XMLHttpRequest compatibility library was not found.]
code: 'auth/internal-error',
message: 'The XMLHttpRequest compatibility library was not found.' }
I think it's some problem related to webpack. I would love any insights on this problem :)
As Gatsby builds pages in a server environment, you can't access Firebase during Gatsby build time. Firebase calls (using the Web SDK) have to happen when the user is on a browser/client environment.
One solution to this problem is creating a function like so:
firebase.js:
import firebase from '#firebase/app';
import '#firebase/auth';
import '#firebase/firestore';
import '#firebase/functions';
const config = {
... firebase config here
};
let instance;
export default function getFirebase() {
if (typeof window !== 'undefined') {
if (instance) return instance;
instance = firebase.initializeApp(config);
return instance;
}
return null;
}
This file returns a function, which returns an instance of Firebase if the user has the global window available (e.g. on the browser). It also caches the Firebase instance to ensure it cannot be reinitialised again (in case of the user changing page on your website).
In your components, you can now do something similar to the following:
import getFirebase from './firebase';
function MyApp() {
const firebase = getFirebase();
}
As Gatsby will try to build this page into HTML during gatsby build, the firebase const will return null, which is correct, as the Firebase Web SDK cannot initialise on a server environment. However, to make use of Firebase on your website, you need to wait until Firebase is available (so the user has to have loaded your website), so we can make use of Reacts useEffect hook:
import React { useEffect } from 'react';
import getFirebase from './firebase';
function MyApp() {
const firebase = getFirebase();
useEffect(() => {
if (!firebase) return;
firebase.auth().onAuthStateChanged((user) => { ... });
}, [firebase]);
}
This works as Firebase is being used in a browser environment and has access to the browser, which is needed for the Web SDK to work.
It does have drawbacks; your compo have to return null in instances when you need Firebase to display content, which will mean your HTML build on the server will not contain any HTML, and it'll be injected via the client. In most cases though, such as an account page, this is fine.
If you need access to data from say Cloud Firestore to display page content, you're best using the Admin SDK to fetch content and add it to GraphQL during Gatsby build. That way it will be available on the server during build time.
Sorry if that was a waffle or not clear!