Authenticate Using Google Sign-In
I'm using Firebase to Sign in a user using Advanced: Handle the sign-in flow manually. I have set up Firebase like so:
firebaseConfig.js
// Config file
import * as firebase from "firebase";
const config = {
apiKey: "api-key",
authDomain: "project-id.firebaseapp.com",
databaseURL: "https://project-id.firebaseio.com",
projectId: "project-id",
storageBucket: "project-id.appspot.com",
messagingSenderId: "sender-id",
appId: "app-id",
measurementId: "G-measurement-id",
};
export default !firebase.apps.length ? firebase.initializeApp(config) : firebase.app();
I then import firebase in another file to authenticate and sign in a user.
LoginUser.js
_isUserEqual = (googleUser, firebaseUser) => {
if (firebaseUser) {
var providerData = firebaseUser.providerData;
for (var i = 0; i < providerData.length; i++) {
if (providerData[i].providerId === firebase.auth.GoogleAuthProvider.PROVIDER_ID &&
providerData[i].uid === googleUser.getBasicProfile().getId()) {
// We don't need to reauth the Firebase connection.
return true;
}
}
}
return false;
}
_onSignIn = googleUser => {
console.log('Google Auth Response', googleUser);
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
var unsubscribe = firebase.auth().onAuthStateChanged(firebaseUser => {
unsubscribe();
// Check if we are already signed-in Firebase with the correct user.
if (!this._isUserEqual(googleUser, firebaseUser)) {
// Build Firebase credential with the Google ID token.
var credential = firebase.auth.GoogleAuthProvider.credential(
googleUser.idToken,
googleUser.accessToken
);
// Sign in with credential from the Google user.
firebase.auth().signInWithCredential(credential).catch(error => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
} else {
console.log('User already signed-in Firebase.');
}
});
}
_signInWithGoogleAsync = async () => {
try {
const result = await Google.logInAsync({
androidClientId: "AndroidClientId",
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
this._onSignIn(result)
return result.accessToken;
} else {
return { cancelled: true };
}
} catch (e) {
return { error: true };
}
}
When I execute the authentication, I receive an error:
Possible unhandled Promise Rejection (id: 0):
TypeError: undefined is not an object (evaluating '_firebaseConfig.default.GoogleAuthProvider.credential') showing that firebase.auth.GoogleAuthProvider is undefined.
Screenshot of the error
Are there any reasons as to why this could be the case? Thanks.
Related
it is showing Unexpected value for STRIPE_SIGNING_SECRET error even after checking it many times in the env file
the terminal shows everything created but it does not reach firebase database I am thinking there is a error in the code
the stripe dashboard also says connected
I am using the forward to local host line in git terminal
webhook code
import { buffer } from "micro";
import * as admin from 'firebase-admin'
//secure a connection to Firebase from backend
const serviceAccount = require('../../../permissions.json');
const app = !admin.apps.length ? admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
})
: admin.app();
// establish connection to stripe
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_SIGNING_SECRET;
if (typeof endpointSecret !== "string") {
console.error("Unexpected value for STRIPE_SIGNING_SECRET");
// potentially throw an error here
}
const fulfillOrder = async (session) => {
//console.log('Fulfilling order', session)
return app
.firestore()
.collection("user")
.doc(session.metadata.email)
.collection("orders")
.doc(session.id)
.set({
amount: session.amount_total / 100,
amount_shipping: session.amount_total_details.amount_shipping / 100,
images: JSON.parse(session.metadata.images),
timestamp: admin.firestore.FieldValue.serverTimestamp(),
})
.then(() => {
console.log(`success: order ${session.id} had been added to db`);
});
};
export default async (req, res) =>{
if(req.method === 'post'){
const requestBuffer = await buffer(req);
const payload = requestBuffer.toString();
const sig = req.headers["stripe-signature"];
let event;
// verify that the event posted came from stripe
try{
event = stripe.webhooks.constructEvent(
payload,
sig,
endpointSecret);
} catch (err) {
console.log('ERROR', err.message)
return res.status(400).send(`Webhook error: ${err.message}`)
}
//handle the checkout event
if (event.type === 'checkout.session.completed') {
const session = event .data.object;
//fulfill the order...
return fulfillOrder(session)
.then(() => res.status(200))
.catch((err) => res.status(400).send(`Webhook error: ${err.message}`));
}
}
};
export const config = {
api: {
bodyParser: false,
externalResolver: true,
},
};
firebase rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write: if false;
allow read: if true;
}
}
}
const endpointSecret = process.env.STRIPE_SIGNNING_SECRET;
Typo: STRIPE_SIGNNING_SECRET
To avoid the next issue, fix the other typo:
const sig = req.headers["stripe-signatur"];
stripe-signature
i have i problem with this file.js ; i try to start the application but the console give me the error on the title of this post (TypeError: _firebase.default.analytics is not a function. (In '_firebase.default.analytics()', '_firebase.default.analytics' is undefined)). I'm using firebase ase database and React Native to create this app based on a common chat where differents user can join and pass messages; This is the code:
import firebase from 'firebase';
import { useCallback } from 'react';
class Fire {
constructor() {
this.init()
this.checkAuth()
}
init = () => {
if(!firebase.apps.length){
var firebaseConfig = {
apiKey: "AIzaSyCSptHIogcurTROMvzp_QB7vQ8srIbnwBk",
authDomain: "login-with-firebase-23e8e.firebaseapp.com",
projectId: "login-with-firebase-23e8e",
storageBucket: "login-with-firebase-23e8e.appspot.com",
messagingSenderId: "1099034898191",
appId: "1:1099034898191:web:b8a3a66be2d5a49d83987a",
measurementId: "G-73M58E50QL"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
}
};
checkAuth = () =>{
firebase.auth().onAuthStateChanged(user => {
if(!user){
firebase.auth().signInAnonymously();
}
});
};
send = messages => {
messages.forEach(item => {
const message = {
text: item.text,
timestamp: firebase.database.ServerValue.TIMESTAMP,
user: item.user
}
this.db.push(message)
})
};
get db() {
return firebase.database().ref("messages");
};
parse = message => {
const {user, text, timestamp} = message.val()
const {key: _id} = message;
const createdAt = new Date(timestamp);
return {
_id,
createdAt,
text,
user
};
}
get = callback => {
this.db.on("child_added", snapshot => callback(this.parse(snapshot)));
};
get uid(){
return (firebase.auth().currentUser || {}).uid;
}
}
export default new Fire();
I guess that my store from vuejs is resetting my authorization. I also get the error message Cannot read property 'home' of undefined in the header component. I don't know why this is not working. I tried debugging.
This is what i have:
In my nuxt.config.js i set plugins to firebase:
plugins: [
'~/plugins/firebase.js'
],
Then here is my firebase.js file:
import firebase from 'firebase/app'
import 'firebase/auth'
var firebaseConfig = {
apiKey: "MYAPIKEY",
authDomain: "AUTHDOMAIN",
databaseURL: "DBURL",
projectId: "PROJECTID",
storageBucket: "STORAGEBUCKET",
messagingSenderId: "MESSAGINGSENDERID",
appId: "APPID",
measurementId: "MEASUREMENTID"
};
!firebase.apps.length ? firebase.initializeApp(firebaseConfig) : ''
export const auth = firebase.auth()
export default firebase
I don't know if it has anything to do with my error but for purpose i just put it in.
Then for my registration page i registrate users with their gmail account i have a function in methods like this:
async registersocial() {
try {
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then((result) => {
this.account.email = result.user.email
this.account.naam = result.additionalUserInfo.profile.given_name
this.account.achternaam = result.additionalUserInfo.profile.family_name
this.$store.dispatch('users/registersocial', this.account).catch(err => {
this.errmsg = err
})
});
} catch(err) {
this.errmsg = err
}
}
And this fires to the store to register a user set a cookie and set the user in the store i do it like so:
async registersocial({ commit }, account) {
const token = await auth.currentUser.getIdToken();
const { email, uid } = auth.currentUser;
Cookie.set('access_token', token);
commit('SET_USER', {
email,
uid
});
this.$router.push('profiel')
const users = firebase.database().ref('Gebruikers/')
users.once('value', function(snapshot){
const naam = account.naam
const achternaam = account.achternaam
const email = account.email
const google = "Google"
var sameemail = null
snapshot.forEach(function(childSnapshot) {
const data = childSnapshot.exportVal()
if(data.Email == email) {
sameemail = email
}
})
if(sameemail != email) {
users.push({
Voornaam: naam,
Achternaam: achternaam,
Email: email,
registerMethod: google
})
}
})
}
And then for the cookie i set i do this:
import JWTDecode from 'jwt-decode';
import cookieparser from 'cookieparser';
export const actions = {
nuxtServerInit({commit}, {req}) {
if(process.server && process.static) return;
if(!req.headers.cookie) return;
const parsed = cookieparser.parse(req.headers.cookie);
const accessTokenCookie = parsed.access_token;
if(!accessTokenCookie) return;
const decoded = JWTDecode(accessTokenCookie);
if(decoded) {
commit('users/SET_USER', {
uid: decoded.user_id,
email: decoded.email
})
}
}
}
Please let me know what i am doing wrong. If u need any more code please let me know.
How can I set session expiration for a Firebase auth session?
By default the session never expires.
I wish for the session to expire after 8 hours of inactivity.
I have read the documentation but cannot figure out how to set session expiration.
My code for signing in the user and performing tasks on sign in and sign out
firebase.auth().signInWithEmailAndPassword(data.email, data.password)
firebase.auth().onAuthStateChanged((user) => {
if (user) {
//Signed in
}else{
//Signed out
}
}
Thanks for all replies!
I have tried but cannot seem to get Firebase-admin to work.
Firebase-db.js
const admin = require('firebase-admin')
const databaseConnection = {
serviceAccountFile: './serviceAccount.json',
databaseURL: 'https://myProject.firebaseio.com/'
}
const serviceAccount = require(databaseConnection.serviceAccountFile)
const app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseConnection.databaseURL
}, 'test')
const database = admin.database(app)
module.exports = database
sessionSignout.js
const functions = require('firebase-functions')
const database = require('../../firebase-db')
const admin = database.admin
exports.sessionSignout = functions
.region('europe-west1')
.pubsub
.schedule('*/15 * * * *')
.timeZone('Europe/Stockholm')
.onRun(async (event) => {
database.ref(`users`)
.once('value', (usersSnapshots) => {
usersSnapshots.forEach((snapshot) => {
const uid = snapshot.key
admin.auth().revokeRefreshTokens(uid)
})
})
}
I get error
Error: function execution failed. Details: Cannot read property 'auth' of undefined
The documentation you linked says that you can use the Firebase Admin SDK to revoke a user's refresh tokens in order to terminate their session. This code must run on a backend you control, which means that you won't be able to do it in the client app. The backend will need to know when the user became "inactive", by whatever definition of that you choose. Wiring this all up is non-trivial, but possible.
Thanks for all the answers!
I just wanted to share my code for others to use.
I already had code in place to accommodate presence awareness.
index.js
import database from './firebase/firebase' //Firebase setup for client
firebase.auth().onAuthStateChanged((user) => {
//Handle login and redirect
if (user) {
//We are logged in
addPresenceAwarenessListener()
}else{
...
}
}
const addPresenceAwarenessListener = () => {
// Create a reference to the special '.info/connected' path in
// Realtime Database. This path returns `true` when connected
// and `false` when disconnected.
database.ref('.info/connected').on('value', (snapshot) => {
// If we're not currently connected, don't do anything.
if (snapshot.val() == false) {
return
}
const uid = firebase.auth().currentUser.uid
//Push last login/logout to user profile
const userLastLoginOutRef = database.ref(`users/${uid}`)
userLastLoginOutRef.onDisconnect().update({lastLoginOut: firebase.database.ServerValue.TIMESTAMP})
.then(() => { userLastLoginOutRef.update({lastLoginOut: firebase.database.ServerValue.TIMESTAMP}) })
})
}
Session handling - expire sessions after n hours (setting "sessExp" in database)
firebase-db.js - Basic Firebase setup for cloud functions
const admin = require('firebase-admin')
const databaseConnection = {
serviceAccountFile: './my-project.json',
databaseURL: 'https://my-project.firebaseio.com/'
}
const serviceAccount = require(databaseConnection.serviceAccountFile)
const app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseConnection.databaseURL
}, 'remindMiNotifier')
const database = admin.database(app)
module.exports = database
sessionSignout.js - Signout user after a specific time period - if specified. Default to eternal session.
const functions = require('firebase-functions')
const moment = require('moment')
const database = require('../../firebase-db')
const admin = database.app
//Import enviroment variable config (.env)
require('dotenv').config()
//Export cron job - deploy: firebase deploy --only functions:sessionSignout
exports.sessionSignout = functions
.region('europe-west1')
.pubsub
.schedule('*/15 * * * *')
.timeZone('Europe/Stockholm')
.onRun(async (event) => {
//Start execution
const now = moment()
const defaultSessionTime = 0 //Eternal session
//Get all users and calculate inactive time - time since last login
let logoutUsersArray = []
await database.ref(`users`)
.once('value', (usersSnapshots) => {
usersSnapshots.forEach((snapshot) => {
const userData = snapshot.val()
const lastLoginOut = (userData.lastLoginOut) ? userData.lastLoginOut : 0
//Only process users that has a login/out time stamp
if(lastLoginOut > 0){
const userSessionTime = (userData.sessExp) ? userData.sessExp : defaultSessionTime
const hoursSinceLastLoginOut = now.diff(lastLoginOut, 'hours')
const logoutUser = ( userSessionTime > 0 && (hoursSinceLastLoginOut > userSessionTime) )
if(logoutUser){
const userId = snapshot.key
const userName = (userData.alias) ? userData.alias : userData.displayName
const email = (userData.email) ? userData.email : ''
const userObject = {
userId,
userName,
email,
lastLoginOut,
diffHours: now.diff(lastLoginOut, 'hours')
}
logoutUsersArray.push(userObject)
}
}
})
})
console.log('logoutUsersArray', logoutUsersArray)
//Collect all promises to carry out
let myPromises = []
// Revoke all refresh tokens for each user
logoutUsersArray.forEach((logoutUser) => {
const uid = logoutUser.userId
myPromises.push(
admin.auth().revokeRefreshTokens(uid)
.then(() => {
return admin.auth().getUser(uid)
})
.then((userRecord) => {
return new Date(userRecord.tokensValidAfterTime).getTime() / 1000
})
.then((timestamp) => {
// Retrieve the timestamp of the revocation, in seconds since the epoch.
console.log('Tokens revoked at: ', timestamp)
return Promise.resolve(true)
})
.catch((err) => {
console.error('Error', err)
return Promise.reject(err)
})
)
})
//Execute promises
console.log('Execute promises')
return Promise.all(myPromises)
.then(() => Promise.resolve(true))
.catch((err) => {
console.error('Error', err)
return Promise.reject(err)
})
})//End sessionSignout
Documentation on firebase-admin can be found here.
I'm trying to do a query to the database, to get all documents of sub-collection "roles" to redirect to different routes.
let userRef1 = db.collection('users').doc(currentUser.uid).collection('roles')
let cont = 0
let rol = ''
let rolStatus = ''
userRef1.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
cont++
rol = doc.data().rol
rolStatus = doc.data().status
});
import { firestore } from "../../firebase";
export const loadCategories = () => {
return (dispatch, getState) => {
firestore
.collection("CATEGORIES")
.get()
.then((querySnapshot) => {
if (!querySnapshot.empty) {
querySnapshot.forEach((doc) => {
console.log(doc.id, "=>", doc.data());
});
}
})
.catch((error) => {
console.log(error);
});
};
};
I have a collection of users including uid just like yours. And for each user, it contains a sub-collection called friends.
Currently, I'm using the following code for my project without having any issues.
module.exports = ({ functions, firestore }) => {
return functions.firestore.document('/users/{uid}').onDelete((event) => {
const userFriendsRef = getFriendsRef(firestore, uid);
userFriendsRef.get().then(snapshot => {
if (snapshot.docs.length === 0) {
console.log(`User has no friend list.`);
return;
} else {
snapshot.forEach(doc => {
// call some func using doc.id
});
}
}
}
};
function getFriendsRef(firestore, uid) {
return firestore.doc(`users/${uid}`).collection('friends');
}
Give it a try to fix your code from
db.collection('users').doc(currentUser.uid).collection('roles')
to
db.doc(`users/${currentUser.uid}`).collection('roles')
It is not clear what you are doing with the rol and status variables. You have declared them as though you are storing a single value, yet you are returning an array of roles and iterating through them.
With regards to getting the results, if your browser supports ES6, then you could do the following:
let userRef1 = db.collection(`users/${currentUser.uid}/roles`)
let cont = 0
let rol;
let rolStatus;
return userRef1.get()
.then(querySnapshot => {
// Check if there is data
if(!querySnapshot.empty) {
// Create an array containing only the document data
querySnapshot = querySnapshot.map(documentSnapshot => documentSnapshot.data());
querySnapshot.forEach(doc => {
let {rol, status} = doc;
console.log(`rol: ${rol} - status: ${status}`);
});
} else {
console.log('No data to show');
}
})
.catch(err => {
console.error(err);
});
Please note: I've only tested this with the Node SDK
// Firebase App (the core Firebase SDK) is always required and must be listed first
import * as firebase from "firebase/app";
// Add the Firebase products that you want to use
import "firebase/auth";
import "firebase/firestore";
const firebaseConfig = {
apiKey: "AIzaSyDNdWutrJ3Axpm-8ngNhzkzcw1g3QvkeFM",
authDomain: "books-7bd8b.firebaseapp.com",
databaseURL: "https://books-7bd8b.firebaseio.com",
projectId: "books-7bd8b",
storageBucket: "books-7bd8b.appspot.com",
messagingSenderId: "385706228283",
appId: "1:385706228283:web:a3c2c9585dd74d54693a1e",
};
firebase.initializeApp(firebaseConfig);
export const firebaseAuth = firebase.auth();
export const firestore = firebase.firestore();
export default firebase;
You should check if it always exists before doing your logic:
userRef1.get().then(function(querySnapshot) {
if(querySnapshot)
{
querySnapshot.forEach(function(doc) {
...you thing
}
})