I want to force a user to reenter its password on a security sensitive step in my app.
I want to use reauthenticateWithCredential but no documentation seems to fit my case using #nativescript/firebase-auth since EmailAuthProvider is always undefined.
This is a similar issue for react.
TypeError: Cannot read property 'credential' of undefined - React-redux-firebase, Firebase Auth
I found the proper sequence to retrieve the user and inject the credential object.
There was also a little catch where reauthenticateWithCredential is coming directly from the user.
import '#nativescript/firebase-auth';
import { EmailAuthProvider } from '#nativescript/firebase-auth';
const user = firebase().auth().currentUser;
const credential = EmailAuthProvider.credential(user.email, password);
try {
await user.reauthenticateWithCredential(credential);
//Good password
}catch(e){
//Wrong password
}
Hope it may be of help to anyone.
Related
I am trying to incorporate the Firebase JS SDK into a managed Expo React Native project. I installed Firebase through npm i firebase and I am using the latest version.
The problem is that whenever I start the expo app, through an Android emulator, I, when passing the input from formik into createUserWithEmailAndPassword first get the auth/network-request-failed error message, but after clicking the signup button several times, more than 10, it somehow works. The user is then added to the Firebase console. After this it works flawlessly, and I can create multiple accounts without fail. However, should I restart the app, then I would have to repeat the steps above.
I have divided the main firebase function to a separate file, and imported it.
The exported file:
import { initializeApp } from 'firebase/app';
import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth';
import firebaseConfig from './app/config/Firebase/firebaseConfig';
let myApp = initializeApp(firebaseConfig);
const auth = getAuth(myApp);
export function signupEmail(email, password) {
console.log(email, password);
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const user = userCredential.user;
console.log('Signed in');
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
});
}
The main parts of the sign-up file:
function handleSignup(values) {
signupEmail(values.email, values.password);
}
<SubmitButton
style={styles.signupButton}
title='SignUp'
onPress={handleSubmit}
/>
onSubmit={(values) => [handleSignup(values)]}
After pressing Signup I get the email and password printed out, as in the signupEmail function. I get the email and password message whether or not it is successful in the end, which I assume implies the problem doesn't lie with formik, since the data is correctly passed to the signupEmail function. Though, from here it often stands idle, sometimes for more than 10s before the network error message comes up. When it is successful, I think, is always instant.
I also have a print-out auth.currentUser button, which returns null whilst the process is loading, and if successful logs out the expected object. Though, sometimes it logs out the object to an account whose email that I didn't add during the current session. I did also add a Sign Out function which turns the auth.currentUser object into null.
I don't know where to go from here, and would appreciate any help!
This issue seems to be related to the Android emulator, Expo Go on my phone worked without issue.
I am using Facebook Login in my Flutter app. I have followed the implementation steps and my app successfully brings up a Facebook Login dialogue and returns an access token on successful login. I don't think the user is actually authenticated on Firebase yet: No new user is listed in the Authentication/Users page on the Firebase console, and calling FirebaseUser user returns null.
The documentation on FlutterFire (https://firebase.flutter.dev/docs/auth/social/) provides this method for authenticating the user on Firebase:
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
Future<UserCredential> signInWithFacebook() async {
// Trigger the sign-in flow
final LoginResult result = await FacebookAuth.instance.login();
// Create a credential from the access token
final FacebookAuthCredential facebookAuthCredential =
FacebookAuthProvider.credential(result.accessToken.token);
// Once signed in, return the UserCredential
return await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
}
I have added this method to my app.
The problem is that even though I have the right package in my pubspec.yaml...
dependencies:
flutter_facebook_auth: "^1.0.0"
...I am getting these errors on the code from FlutterFire:
" Undefined class 'FacebookAuthCredential' "
and
" The method 'credential' isn't defined for the type 'FacebookAuthProvider'. "
Other methods from flutter_facebook_auth work fine, though (eg FacebookAuth.instance.login())
I would appreciate any help!
Solved it! I just needed to add this plugin:
firebase_auth_platform_interface: ^3.1.0
(https://pub.dev/packages/firebase_auth_platform_interface)
This gave me access to the FacebookAuthCredential object.
The FacebookAuthProvider.credential() method still wasn't available, but I replaced it with FacebookAuthProvider.getCredential() and it worked as it is supposed to.
I am having difficulty using the FirebaseApp (a 3rd party API) to generate an authentication token that can be passed to a sidebar and used by the client to login and access my Firebase Database client-side.
I'm trying to use this tutorial but cannot get it working without using a database secret (which is being depreciated) in makeToken(). I'd prefer to use a service account as reflected in this tutorial. When I look at the difference between the tokens generated, the first 2 pieces separated by a '.' are identical, the last piece after the final '.' is different. The lengths are the same as well. eg:
//Example Generated by Database Secret: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2U=
//Example Generated by Service Account: TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBv.ZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=.IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbml=
I can generate the OAuth access token, pass it to FirebaseApp and generate an authentication token, but when it is passed client-side and I attempt to authenticate I get an error: Login Failed! Error: INVALID_TOKEN: Failed to validate MAC.
It seems like there is a lot of misinformation and conflicting information on how this should be done.
I have a getFirebaseService() function server-side that uses Apps Script OAuth2 Library to get an access token.
function getFirebaseService() {
return OAuth2.createService('Firebase')
// Set the endpoint URL.
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the private key and issuer.
.setPrivateKey(fb_PRIVATE_KEY) //Service account private key
.setIssuer(fb_SERVICE_EMAIL) //Service account email
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scopes.
.setScope('https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/firebase.database');
}
I have a makeToken() function server-side that gets an authentication token from Firebase using the OAuth access token. I am able to use the service.getAccessToken() OAuth token server-side to access and store data. So that works, I guess my issue is creating a client auth token that's more restrictive.
function makeToken(){
var service = getFirebaseService();
if (service.hasAccess()) {
return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //Database Secret Works: "AAslhfi3MYACCESSTOKEN2930hf03ah4th8" but is being depreciated.
.createAuthToken(Session.getActiveUser().getEmail());
} else {
Logger.log("makeToken: " + service.getLastError());
}
}
Then client-side, from the sidebar, I try to authenticate with a custom auth token retrieved server-side from makeToken().
var userAuthToken;
google.script.run.withSuccessHandler(function (requestAuthToken) {
userAuthToken = authenticateClient(requestAuthToken)
}).makeToken();
function authenticateClient(userRequestToken) {
var ref = new Firebase(fb_URL);
ref.authWithCustomToken(userRequestToken, function (error, authData) {
if (error) {
console.log("FB Login Failed!", error); //Error below come from here.
}
else {
console.log("FB Login Succeeded!", authData);
}
});
return ref.authData.auth;
}
This results in Login Failed! Error: INVALID_TOKEN: Failed to validate MAC..
Edit: Is it possible FirebaseApp is incorrectly generating the JWT Authentication Token?
Edit2: I think the above edit is unlikely as I attempted to use the GSApp library and had the same issue. It only seems to want the depreciated database secret, not a service account OAuth.
Alright, so after a very long day I figured it out. I'm going to lay out what I ended up using for libraries and what the issue was (see the third library). The main problem was essentially that the tutorial was outdated and no a lot of people use Firebase in apps script.
OAuth2 (Server-side)
Link
I didn't have to change anything here! It was working fine and never an issue.
FirebaseApp (Server-side)
Link
This is a nice library and I stuck with it because it worked well (once I got it there). I had to make a change to my original code that came from the tutorial I mentioned. My code ended up like this and worked:
if (service.hasAccess()) {
return FirebaseApp.getDatabaseByUrl(fb_URL, service.getAccessToken()) //get OAuth Token
.createAuthToken(Session.getEffectiveUser().getEmail(), null, serviceAccount.client_email, serviceAccount.private_key);
//... Added the null, private key, and service email parameters.
Firebase (Client-side)
Link
Alright, so this is where my main issue was -- The tutorial I followed for client-side setup was old. I had to upgrade the code on my own to use the new 3.x version:
<script src="https://www.gstatic.com/firebasejs/5.8.2/firebase.js"></script>
// Initialize Firebase
var config = {
apiKey: "<Web API Key>",
authDomain: "<Project ID>.firebaseapp.com",
databaseURL: "https://<DB URL>.firebaseio.com/"
};
firebase.initializeApp(config);
With this firebase instance I was able to update my original authenticateClient() method:
function authenticateClient(userRequestToken) {
firebase.auth().signInWithCustomToken(userRequestToken).catch(function(error) {
// Handle Errors here.
console.error("authClient: ", error.code, error.message);
});
return {
uid: firebase.auth().currentUser.uid,
metadata: {
lastSignInTime: firebase.auth().currentUser.lastSignInTime
}
};
}
That's it! I now have a firebase instance with a signed in user via JWT Custom Token! I came across a few people with similar issues an I hope this helps.
I am using Firebase Authentication with Email and Password
I would like to know if i can 'lookup' a user by email only while also not being signed in as a user
The reason I'd like to do this is, is to simply identify if I am already a user of the system, using an email address only
I looked at this older thread but it appears to be the previous version of Firebase
Is it possible to do this in the current Firebase, or my alternative would be to keep this information available (and open to all?) to find out if a given email is part of my system?
I use fetchProvidersForEmail(email)
and if the result return as empty array then, this email hasn't been use to sign up.
firebase.auth().fetchProvidersForEmail(email)
.then(providers => {
if (providers.length === 0) {
// this email hasn't signed up yet
} else {
// has signed up
}
});
You can look up user information by email:
firebase.auth().getUserByEmail(email)
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully fetched user data:', userRecord.toJSON());
})
.catch(function(error) {
console.log('Error fetching user data:', error);
});
I'd like to make things more clear that this method does not exist — one could be looking for it in the firebase client library, in which it has never been available in the first place and it wouldn't be a good idea to have anyway. This method is part of the admin SDK, so in order to call the method, you need to run it on the server, and invoke it from the client. OP didn't scope the question to firebase client library, so my answer is still correct.
Retrieve user data
The new method of creating users with email password returns a value whether the given email address is already in use. See here
import { fetchSignInMethodsForEmail } from 'firebase/auth'
fetchSignInMethodsForEmail(auth, registerEamil).then((result) =>{
console.log("result", result);
if (result.length === 0) {
Navigate("/authentication/select_role/" +
registerEamil)
} else {
Navigate('/')
}
Server side option:
https://cloud.google.com/identity-platform/docs/reference/rest/v1/projects.accounts/lookup
POST https://identitytoolkit.googleapis.com/v1/projects/{targetProjectId}/accounts:lookup
{ "email": ["rodneydangerfield#stackoverflow.kom"] }
As for today 2021 Nov. 18th, there is no way provided by the Firebase SDK to fetch a user by email.
(1) Question:
Is there a way to read user email having the uid? (permitted only for super user or server)
Ps.: I don't want to save in the Realtime database, because even though only the current user can change it, he can erase or put some fake email..
(2) Problem:
I'm trying to retrieve user email with GoogleAuthProvider in Firebase v3
Thats the code I'm using:
signInWithGoogle(): Promise<any> {
let provider = new firebase.auth.GoogleAuthProvider();
provider.addScope("https://www.googleapis.com/auth/userinfo.email");
return firebase.auth().signInWithPopup(provider)
.then((result) => {
console.log(result.user.email);
console.log(result.credential);
let token = result.credential.accessToken;
return this.createOrUpdateUser(result.user, token);
});
}
The result:
result.user.email # null
result.user.providerData[0].email # correct_email#gmail.com
Even though the email is in the providerData, it is not attached to the auth..
Is it a firebase bug or can I fix it somehow?
Thanks!
The 3.2.0 web sdk launched yesterday should automatically ask for the profile scope when signInWithPopup for google provider. Try deleting the test user and sign in again. The top level email should be populated.