I'm trying to fetch a list of all the users in my web app, but I keep receiving this error:
"TypeError: utils_firebase_WEBPACK_IMPORTED_MODULE_2_.auth.listUsers is not a function"
I copied exactly from Firebase documentation, and below is my code.
auth prints out "AuthImpl {app: FirebaseAppImpl, heartbeatServiceProvider: Provider, config: {…}, currentUser: null, emulatorConfig: null, …}", so I know that auth exists.
import { useEffect } from "react";
import { auth } from "../utils/firebase";
function users() {
const listAllUsers = (nextPageToken) => {
console.log(auth);
auth
.listUsers(1000, nextPageToken)
.then((listUsersResult) => {
listUsersResult.users.forEach((userRecord) => {
console.log("user", userRecord);
});
if (listUsersResult.pageToken) {
listAllUsers(listUsersResult.pageToken);
}
})
.catch((error) => {
console.log("Error listing users:", error);
});
};
useEffect(() => {
listAllUsers();
}, []);
return <div>users</div>;
}
export default users;
Can someone help me with this? Thanks!
I tried to look at the documentation from Firebase, but with no luck
listUsers() is a method from the Admin SDK and not from the JS SDK. The page you copied the code from documents the Admin SDK methods for the Authentication Service.
There isn't any corresponding method in the JS SDK because, for security reasons, it is not possible to let a user directly listing all users of a Firebase project from a front-end.
If you want to list all users of your Firebase project from your front-end you can write a Callable Cloud Function that uses the listUsers() Admin SDK's method. It's then up to you to verify who can call this Cloud Function.
Related
Not sure if anyone has any experience with getstream and react native.
I followed there tutorial to implement getstreams SDK into my existing app and its working great but I'm stuck on tokens. I've successfully set up firebase so when a new user signs up I can see there UID and information over on both firebase auth and getstream but I'm hung up on my frontend getting the user to sign in on the chat with there token. I set up firebase with there extension but still having issues. Works great with dev.tokens but just can't get past this part. Is there any examples out there or better documentation for this? Thank you!
Only documentation I can find.. not specific to react native
https://getstream.io/chat/docs/react/tokens_and_authentication/
This is currently how I initialize my user.. the user token is hard coded in my chat config file.
// useChatClient.js
import { useEffect, useState } from 'react';
import { StreamChat } from 'stream-chat';
import { chatApiKey, chatUserId, chatUserName, chatUserToken } from './chatConfig';
const user = {
id: chatUserId,
name: chatUserName,
};
const chatClient = StreamChat.getInstance(chatApiKey);
export const useChatClient = () => {
const [clientIsReady, setClientIsReady] = useState(false);
useEffect(() => {
const setupClient = async () => {
try {
chatClient.connectUser(user, chatUserToken);
setClientIsReady(true);
// connectUser is an async function. So you can choose to await for it or not depending on your use case (e.g. to show custom loading indicator)
// But in case you need the chat to load from offline storage first then you should render chat components
// immediately after calling `connectUser()`.
// BUT ITS NECESSARY TO CALL connectUser FIRST IN ANY CASE.
} catch (error) {
if (error instanceof Error) {
console.error(`An error occurred while connecting the user: ${error.message}`);
}
}
};
// If the chat client has a value in the field `userID`, a user is already connected
// and we can skip trying to connect the user again.
if (!chatClient.userID) {
setupClient();
}
}, []);
return {
clientIsReady,
};
};
The next step is to request the token from the Firebase cloud function (ext-auth-chat-getStreamUserToken), and then initialise the current user with that token.
There is a guide and video showing how to do this using the Stream Chat Flutter SDK:
https://getstream.io/chat/docs/sdk/flutter/guides/token_generation_with_firebase/
https://youtu.be/Dt_taxX98sg
I am trying to test a firebase app locally.
I am running the test with firebase emulators:exec --only firestore 'mocha -r ts-node/register src/**/*.spec.ts
In my spec, I import #firebase/testing and setup my app and followed the directions from
https://firebase.google.com/docs/rules/unit-tests
I have a FirebaseService which is a singleton wrapper for my methods into which I inject my firebase app.
In production, I'll inject the firebase, and it gets initialized in the FirebaseService in testing, I initialize outside of the service.
The wrapper is fairly simple
export const FirebaseService = (function(): FirebaseSrvc {
let firebase;
const fbServiceObj: FirebaseSrvc = {
getInstance: (firebaseConfig, firebaseCore, initialize) => {
firebase = firebaseCore;
if (initialize && firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
return fbServiceObj;
},
createActivity: async (title: string) => {
try {
const firebaseUid = firebase.auth().currentuser.uid;
const newActivity: ActivityProps = {
title,
created_at: 123445,
created_by: firebaseUid,
public: false,
available_to: [firebaseUid],
};
console.log(' before create', newActivity);
const createResponse = await firebase
.firestore()
.collection('activities')
.doc(stringToSafeId(title))
.set(newActivity);
console.log('create response', createResponse);
return true;
} catch (e) {
console.log('error creating activity', e);
}
},
getActivity: async (title: string): Promise<ActivityProps> => {
try {
const actResponse: DocumentReferenceTo<ActivityProps> = await firebase
.firestore()
.collection('activities')
.doc(stringToSafeId(title))
.get();
return actResponse as ActivityProps;
} catch (e) {
console.log('error getting activity from firebase', e);
}
},
};
return fbServiceObj;
})();
The test I am attempting to run is
import * as firebase from '#firebase/testing';
import { assert } from 'chai';
import 'mocha';
import * as appConfig from '../../app-dev.json';
import { FirebaseService } from '../services/FirebaseService';
firebase.initializeTestApp({ ...appConfig.expo.extra.firebase, auth: { uid: 'random', email: 'test#test.com' } });
describe('Activity', async () => {
const fb = FirebaseService.getInstance(appConfig.expo.extra.firebase, testApp, false);
const activityData = new Activity(fb);
beforeEach(async () => await firebase.clearFirestoreData({ projectId }));
it('should create a new activity', async () => {
await activityData.set('test-activity'); // this runs FirebaseService.createActivity
const findActivity = await activityData.get('test-activity'); // this run FirebaseService.getActivity
assert(findActivity.title === 'test-activity');
});
});
When I run the test I get an error
Your API key is invalid, please check you have copied it correctly.] {
code: 'auth/invalid-api-key',
message: 'Your API key is invalid, please check you have copied it correctly.'
}
I can confirm that the API key which is passed into firebase.initializeTestApp matches the Web API Key in my firebase console.
I have also downloaded the google-services.json from my firebase console and lists
{
"api_key": [
{ "current_key": different_from_web_key}
]
}
And I have replaced my existing key with this new key, I still get the same error.
I have also tried setting up initializeTestApp({ projectId }) which is how the example from firebase docs sets it up, and I receive the same result.
I am using the same project details to run a project locally in android studio, and I am able to authenticate and write to firestore, so the API key I am using does work, but it appears to have issues being used in the test app.
This usually doesn't have a specific way to solve it. It might be that even a new copy and paste of the API key to the parameters, might make it work and the error to disappear.
I would recommend you to take a look at the following posts from the Community, that have some possible fixes for the error that you are facing.
Firebase Error: auth/invalid-api-key, Your API key is invalid, please check you have copied it correctly
Invalid API Key supplied using Firebase
In addition to that, since Firebase has free support offers, I think you reaching out to the Firebase support would help you fix this quickly. You should be able to contact directly for free.
Let me know if the information helped you!
I've a project in which I used to authenticate the users with firebase-auth.In my project users can not create their accounts on their own.Only admin have the privilege to add the user accounts.
In order to use onAuthStateChanged() function I must use firebase-auth in my page.But the issue is because of using firebase-auth on client side one can esaily create accounts by running createUserWithEmailAndPassword() function on the console without having the admin privilege.
Now how can I restrict the people from using createUserWithEmailAndPassword() function on client side?
The only way you can stop clients apps from creating accounts is to disable all authentication providers for your project in the Firebase console. You could write an auth onCreate Cloud Function that attempts to figure out if a new account was created by client or admin code if you want to try to delete it immediately.
I think you can add a claim once the user is added, via a cloud function, which requires authorization, so that if the user doesn't have that claim he can't use the app or can't login.
In 2022 with Firebase Auth with Identity Platform and blocking functions, we can accomplish that the following way:
Create an HTTP function that receives email, password and displayName, and creates user using firebase-admin:
import { https } from 'firebase-functions';
import { getAuth } from 'firebase-admin/auth';
import cors from 'cors';
const auth = getAuth();
// Register an HTTP function with the Functions Framework
export const signupUser = https.onRequest((req, res) => {
const options = {
origin: 'http://localhost:3000'
};
cors(options)(req, res, () => {
console.log('all good');
auth
.createUser({
email: 'example#email.com',
emailVerified: false,
password: 'secretPassword',
displayName: 'John Doe',
disabled: false,
})
.then((userRecord) => {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully created new user:', userRecord.uid);
})
.catch((error) => {
console.log('Error creating new user:', error);
});
// Send an HTTP response
res.send('OK');
});
});
Modify response and origin in CORS as you need.
Now create a blocking beforeCreate function and check for user's display name, if there is no display name, throw an error:
import { auth } from "firebase-functions";
import { initializeApp, applicationDefault } from 'firebase-admin/app';
import { getAuth } from 'firebase-admin/auth';
import postmark from 'postmark';
const app = initializeApp({
credential: applicationDefault(),
projectId: 'your_project_id',
});
const tnc = getAuth(app);
export const signUp = auth
.user().beforeCreate((user, context) => {
if (!user.displayName) {
throw new auth.HttpsError('permission-denied');
}
});
This will work because there is no way to include "display name" when signing up via client side
So you, in short, point is to create a Cloud Function that will register users and make sure to add the check to beforeCreate for something that you know is only possible to do on server-side via firebase-admin sdk.
EDIT: CORRECTION
Just found out you can now disable client side signup from Firebase Console if you have Auth + Identity Platform
I am trying to get the Firebase authentication access token within a React Native application so that I can authenticate my API calls to a custom server. The Firebase documentation says I should get this token by using auth().currentUser.getIdToken(); however currentUser returns null.
I've tried to use getIdToken() in multiple areas of the application. I know the access token is generated as I can see it in the logs while using expo (user.stsTokenManager.accessToken).
Why is currentUser returning null and how can I get the accessToken?
You need to wrap user.getIdToken() inside of firebase.auth().onAuthStateChanged for user to be available. You can then use jwtToken in your header to authenticate your API calls. You need to import your Firebase configuration file for this to work.
let jwtToken = firebase.auth().onAuthStateChanged(function(user) {
if (user) {
user.getIdToken().then(function(idToken) { // <------ Check this line
alert(idToken); // It shows the Firebase token now
return idToken;
});
}
});
Just putting await before will work too just like this:
await auth().currentUser.getIdToken();
getIdToken returns a promise
firebase.auth()
.signInWithCredential(credential)
.then(async data => {
const jwtToken = await data.user?.getIdToken();
console.log(jwtToken);
})
Hook example
Unfortunately, its not reliable to directly get the token. You first have to listen to the authentication state change event which fires upon initialization since its asynchronous.
import {auth} from '../utils/firebase'
import {useState, useEffect} from 'react'
export default function useToken() {
const [token, setToken] = useState('')
useEffect(() => {
return auth().onAuthStateChanged(user => {
if (user) {
user.getIdToken(true)
.then(latestToken => setToken(latestToken))
.catch(err => console.log(err))
}
})
}, [])
return token
}
then use like so in your functional component
const token = useToken()
useEffect(() => {
if (token) {
// go wild
}
}, [token])
I'm using AngularFire2 (2.0.0-beta.2) incombination with angular2 (2.0.0-rc.4). Using Angularfire I can programatically create a user (email/password) with
angularFire.auth.createUser({email : this.email, password; this.password})
That part works as expected. Subsequently, I would like to update either the email address or password. I've examined the AngularFire source and there doesn't seem to be a mechanism to do this. Am I correct in this assessment? And if I'm correct, should I expect to see a mechanism in upcoming releases or should I just use the native Firebase mechanisms?
You are looking to use $firebaseAuth(). Just inject it in your controller and go with
$firebaseAuth().$updateEmail("email#email.com");
$firebaseAuth().$updatePassword("newpass123");
I think my answer will be helpful, Password can be changed by firebase-admin using cloud function you will just have to pass email and new password from the client-side(Angular, ionic, ...)
Cloud function:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
const cors = require('cors')({ origin: true });
export const resetUserPassword = functions.https.onRequest( async (req, res) => {
return cors( req, res, async () => {
const email = req.body.data.email;
const password = req.body.data.password;
admin.auth().getUserByEmail(email)
.then((getUserRecord) => {
admin.auth().updateUser(getUserRecord.uid, {
email,
password
})
.then(function(userRecord) {
res.send({
status: 200,
data: userRecord
})
})
.catch(function(error) {
res.send({
status: 500,
data: error
})
});
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
})
});
Client side code(IONIC):
import { AngularFireFunctions } from '#angular/fire/functions';
export class AuthService {
constructor(
private functions: AngularFireFunctions
) {}
resetUserPassword() {
const userNewCredential = {email: 'user-email', password: 'your-new-password'};
this.functions.httpsCallable('resetUserPassword')
(userNewCredential).toPromise().then((updatedUser) => {
console.log(updatedUser);
}).catch((error) => console.log(error));
}
I'm going to try an answer my own question. I think that the AngularFire2 public API's are missing some functionality related to firebase authentication. For example I don't think the present version of AngularFire (2.0.0-beta2) has the ability to update the email address or password, or send the password reset email. I think the solution to this present shortcoming is to get the native firebase objet and just use the native firebase methods to resolve. However, I haven't been able to figure out how to get access to the native FireBase object using AngularFire2. I've posted this question to see if anyone can help me do that.