I am using firebase in my react native application in which i am signing into the firebase using signInWithCustomToken in which i am passing the token that is received from my server.
Once the signInWithCustomToken is successful i checked the uid of that user. Instead of getting the uid i am getting the user email id like below
_auth: Auth {_app: App, _customUrlOrRegion: undefined, namespace: "auth", _user: User, _settings: null, …}
_user: {metadata: {…}, providerData: Array(0), phoneNumber: null, photoURL: null, displayName: null, …}
displayName: (...)
email: (...)
emailVerified: (...)
isAnonymous: (...)
metadata: (...)
phoneNumber: (...)
photoURL: (...)
providerData: (...)
providerId: (...)
refreshToken: (...)
uid: "student#gmail.com"
The uid should be something like below AbHH6vQvIDS8uPXw3ZPljQnWFRp3 but i am receiving the email in uid
For custom tokens, the UID is whatever you specify in the token on your server in the call to admin.auth().createCustomToken(uid) (or equivalent for your platform). So it seems like your server-side script is passing the email address instead of a generated/obfuscated ID.
Related
I have an Email, Google and Facebook authentication in Firebase and I want to create a Firestore records of users who sign in with Google or Facebook.
My code is as follows:
exports.onUserCreate = functions.auth.user().onCreate(async (user) => {
if (user.providerId !== 'password') {
console.log('onusercreate start')
await admin.firestore().collection('users').doc(user.uid).set({
email: user.email,
photoURL: user.photoURL,
user_name: '',
full_name: user.displayName,
phone_number: '',
uid: user.uid,
friends_count: 0,
posts: 0,
fcm_token: '',
chats_initiated: [],
rank: 'Goon',
rah_points: 0,
last_seen: '',
push_notification_settings: 'ON',
})
}
})
This code throws the following error in the console:
Unhandled Rejection (FirebaseError): No document to update: projects/teambeforeself-b1c79/databases/(default)/documents/users/oe7d4MMaTyQ6kNDxuEdqGeamLeQ2
The auth user is created with google sign in but the Firestore document is not being created.
The logs in Firebase Cloud Functions are as follows:
2:58:51.762 pm onUserCreate Function execution started
2:58:52.116 pm onUserCreate onusercreate start
2:58:53.454 pm onUserCreate Function execution took 1693 ms, finished with status: 'ok'
Whenever a firebase user creates an account I would like to send the verification mail to my own mail instead of the created user their email.
This is my code:
export function onAuthStateChanged(callback) {
auth.onAuthStateChanged((user) => {
let userinfo = { uid: "", token: "", name: "", email: "", verified: "" }
if (firebaseUser) {
userinfo = {
uid: user.uid,
token: user.ma,
name: user.displayName,
email: user.email,
verified: user.emailVerified
}
if (!user.emailVerified) {
user.sendEmailVerification();
}
}
})
}
And I tried to edit this line:
user.email = "mymail#gmail.com"
user.sendEmailVerification();
But 'user' is read-only
Thanks
Firebase Authentication will only send an email to the account that is specified in the user profile. You can't configure it to send the email elsewhere.
Options I can quickly see:
Either send an additional email to your own a address when you call user.sendEmailVerification().
Or use your own verification flow entirely, not depending on Firebase Authentication's user.sendEmailVerification() method.
Firebase has no specific support for either of these actions, and you'll have to code them yourself as you'd do with any requirement to send email. If you're new to this, you might want to look at using Cloud Functions to send email.
I'm building a web app using Angular for the frontend and Cloud Functions for backend stuff. Also using Firebase Authentication to register and login users. To persist data I'm using Cloud Firestore.
The register part is used on Cloud Functions. There I call admin.auth().createUser() to set the user credentials for the Auth user as well as for the user document that I add to Cloud Firestore.
My problem is that I hash the password value on the frontend before the HTTP request to Functions is sent. I do this because of safety reasons. But how can I revert the hash, so I can write the raw password into createUser()?
Actually I save the hashed password and after that I can't login with the created user, because it's the hashed value.
My function in Cloud Functions:
exports.createUser = async (req, res) => {
try {
const user = req.body;
console.log(user.password);
const userRecord = await admin.auth().createUser({
email: user.mail,
emailVerified: false,
password: user.password,
displayName: user.firstname + ' ' + user.lastname,
photoURL: "http://www.example.com/12345678/photo.png",
disabled: false
}).then(async (userRecord) => {
console.log(userRecord.password);
console.log(userRecord);
return await userCollection.doc(userRecord.uid).set({
uid: userRecord.uid,
firstname: user.firstname,
lastname: user.lastname,
photoURL: userRecord.photoURL,
dateOfBirth: user.dateOfBirth,
sex: user.sex,
city: user.city,
activities: user.activities,
offers: user.offers
})
})
console.log("Successfully created new user:");
return res.status(200).send(userRecord);
}
catch (error) {
console.log("Error creating new user:", error);
return res.send(false);
}
The hashing on the frontend looks like this (using ts-md5):
password: Md5.hashStr(this.registerForm.value.registerFormPassword)
Is there a method to reverse the hash or a method from Firebase Auth to hash the password on the client side and a counterpart to revert it on the server side?
I searched the internet for answers but can't find anything to this topic, so could it be that this is absolutely the wrong way with hashing the password? And if so, what's good practise in such cases?
I have a cloud function that is triggered by Auth user creation. I look up the user data (email, name, etc) to populate my DB. It suddenly stopped working for the 'email/password' Auth provider type. The admin.auth().getUser(uid) now returns a userRecord which contains undefined/null values for most fields. This seemingly stopped working out of nowhere in Production after functioning for several weeks, is there any possible explanation?
exports.createUser = functions.auth.user().onCreate((user) => {
return createEmailUser(user);
});
function createEmailUser(user) {
const uid = user.uid;
return admin.auth().getUser(uid)
.then(function(userRecord) {
console.log(userRecord);
const email = userRecord.email;
const fullName = userRecord.displayName;
admin.database().ref('users/' + uid).set({
email: email,
name: fullName
});
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
}
In the past, the userRecord object contains valid email and displayName values. Now, I see an object like this:
UserRecord {
uid: 'Lrtj8zafsnYjZl4ckMgwNkgEiVH2',
email: undefined,
emailVerified: false,
displayName: undefined,
photoURL: undefined,
phoneNumber: undefined,
disabled: false,
metadata:
UserMetadata {
creationTime: 'Wed, 09 Jan 2019 21:40:31 GMT',
lastSignInTime: null },
providerData: [],
passwordHash: undefined,
passwordSalt: undefined,
customClaims: undefined,
tokensValidAfterTime: 'Wed, 09 Jan 2019 21:40:31 GMT' }
As users are registered with Email/Password method, then there is only the email address available in userRecord. Other sign-in providers might have different data at user creation.
What you can do here is to check user data at profile creation, and update profile with updateUser if anything is missing:
function createEmailUser(user) {
const uid = user.uid;
admin.auth().updateUser(uid, {
phoneNumber: "+11234567890",
displayName: "Foo Bar"
})
.then(function(userRecord) {
console.log(userRecord);
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
}
I have written a Google Cloud Function Express app and a command-line tool that uses Node.js on my local Mac.
Calling myclitool login, a one-time prompt asks the user for their email and password. The CLI tool sends the email and password inside the request body using an HTTP POST request to the Express server, over SSL.
The server will send back a private API Key (generated by a trigger function at the time the user was registered) that will be written to ~/.myclitoolrc and will be used for all subsequent calls to my API endpoint.
Each subsequent call from the CLI tool will lookup the private API Key in the Firestore accounts collection, and authenticate on per API call basis.
admin.firestore()
.collection('accounts')
.where('privateApiKey', '==', privateApiKey)
.get() // and so on
So far, the following code will locate the admin.auth.UserRecord.
Service.prototype.signin = function signin(email, password) {
return new Promise(function(resolve, reject) {
admin.auth().getUserByEmail(email)
.then(userRecord => {
console.log(userRecord);
resolve('some value later');
})
.catch(err => {
reject(err);
});
});
};
The Firebase documentation says:
https://firebase.google.com/docs/reference/admin/node/admin.auth.UserRecord
passwordHash (string or null)
The user’s hashed password (base64-encoded), only if Firebase Auth
hashing algorithm (SCRYPT) is used. If a different hashing algorithm
had been used when uploading this user, as is typical when migrating
from another Auth system, this will be an empty string. If no password
is set, this will be null. This is only available when the user is
obtained from listUsers().
passwordSalt (string or null)
The user’s password salt (base64-encoded), only if Firebase Auth
hashing algorithm (SCRYPT) is used. If a different hashing algorithm
had been used to upload this user, typical when migrating from another
Auth system, this will be an empty string. If no password is set, this
will be null. This is only available when the user is obtained from
listUsers().
The UserRecord is retrieved and contains the SCRYPTd passwordHash and passwordSalt properties.
UserRecord {
uid: 'kjep.[snip]..i2',
email: 'email#example.com',
emailVerified: false,
displayName: undefined,
photoURL: undefined,
phoneNumber: undefined,
disabled: false,
metadata:
UserMetadata {
creationTime: 'Thu, 12 Apr 2018 09:15:23 GMT',
lastSignInTime: 'Thu, 03 May 2018 03:57:06 GMT' },
providerData:
[ UserInfo {
uid: 'email#example.com',
displayName: undefined,
email: 'email#example.com',
photoURL: undefined,
providerId: 'password',
phoneNumber: undefined } ],
passwordHash: 'U..base64..Q=',
passwordSalt: undefined,
customClaims: undefined,
tokensValidAfterTime: 'Thu, 12 Apr 2018 09:15:23 GMT' }
There appears to be no verification functions as part of the Firebase Admin SDK admin.auth().
Should I implement the SCRYPT verification myself by finding an algorithm or ready-made Node module, or should I take the absence of any verification functions as a sign that this is not the best approach?
If so, please recommend a better design, bearing in mind this is a prototype project and to implement full Oauth2 would be quite time consuming.
As requested in the comments, here is some example code for accessing Cloud Firestore using Node.js via the Firebase Javascript SDK (enforces security rules).
There is a bug filed in v4.13.0 (now closed). I haven't tested 4.13.1 yet, but the fix has been merged into the master branch. If it doesn't work, you should try v4.12.0.
const firebase = require('firebase');
require("firebase/firestore");
// Initialize Firebase
// You get these details from the Firebase Console
let config = {
apiKey: "yourAPIkey",
authDomain: "yourAuthDomain",
databaseURL: "https://yourProjectID.firebaseio.com",
projectId: "yourProjectID",
messagingSenderId: "yourId"
};
firebase.initializeApp(config);
let email = 'yourUser#example.com';
let password = 'yourVerySecurePassword';
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(error => {
console.log(error);
});
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('I am logged in');
// Initialise Firestore
const firestore = firebase.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
return firestore
.collection('accounts')
.where('privateApiKey', '==', privateApiKey)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((documentSnapshot) => {
if (documentSnapshot.exists) {
console.log(documentSnapshot.id);
}
});
});
} else {
// User is signed out.
// ...
}
});