72

Not sure if I am doing something wrong but using this api https://www.firebase.com/docs/security/simple-login-email-password.html I can successfully create a user - according to the return message, but I can not see that user anywhere in the Forge console. How do you know what users are registered?

Should I be taking the return user ID and creating my own user object in Firebase or is this duplication unnecessary. I do need to add some additional user properties so perhapes I will need to do this anyway.

0

7 Answers 7

83

When using email / password authentication in Firebase Authentication (previously known as Firebase SimpleLogin), your user's email and password combination is securely stored separately from the data actually stored in your Firebase.

This barrier between the data in your Firebase and your users' email / password hash combinations is by design: we want to make it easier for you to (1) develop your application, (2) prevent any accidental user credential leaks, and (3) still give you total flexibility with how to store your user data in Firebase.

That means that we only store the email address / password hash combination and nothing else, so it is up to you to decide how to store actual user data in your Firebase. As you suggested, you should be taking the user id and storing that data in your Firebase in a location such as /users/$id, and using the Firebase Security Rules Language to determine read / write access to that data. Your user's unique id and email are already in the auth variable you'll use when writing rules.

12
  • 3
    Thanks for the information - I assume there is a dependency there though, if the data I store per user goes out of synch, say accidentally deleted, how would I know who could currently access my application? Its good that the data is separate but surely thats negated by the fact I can't see it from an administration POV?
    – markbarton
    Feb 5, 2013 at 14:22
  • 6
    Listing all created users and deleting users looks like a must have! Feb 17, 2013 at 12:32
  • 7
    The user list accessible via console is now back in the new Google's Firebase Jun 18, 2016 at 21:39
  • 3
    This is a must have... Kinda defeats the purpose of a user database if the admin SDK can't transverse the users.
    – Rojuinex
    May 16, 2017 at 2:24
  • 3
    Thanks for the answer Frank. However, if the separate user database that you are talking about only stores email/password combinations (not any other user info), why under the Manager Users section (firebase.google.com/docs/auth/web/manage-users) do they mention the user.updateProfile method with the ability to save a displayName and photoURL? Where does this info get stored then? It's not saving in my Firestore - I checked - so I'm assuming it is in that separate DB. What's the point of this method if the current user is the only one who can see it?
    – dwilt
    Dec 6, 2017 at 16:42
11

Here i created an Android program to do what Rob said for firebase beginner(like me) out there.this program first store the username of the signedUp or signedIn user and then display them in a listView

SignInActivity.java

public class SignInActivity extends BaseActivity implements View.OnClickListener,View.OnKeyListener{

    private DatabaseReference mDatabase;
    public static FirebaseAuth mAuth;
    private static final String TAG = "MainActivity";

    EditText usernameField;
    EditText passwordField;
    TextView changeSignUpModeTextView;
    Button signUpButton;
    ImageView logo;
    RelativeLayout relativeLayout;

    Boolean signUpModeActive;
    static ArrayList<String> userList = new ArrayList<>();

    @Override
    public void onStart() {
        super.onStart();

        // Check auth on Activity start
        if (mAuth.getCurrentUser() != null) {
            onAuthSuccess(mAuth.getCurrentUser());
        }
    }
    @Override
    public boolean onKey(View view, int i, KeyEvent keyEvent) {

        if(i == keyEvent.KEYCODE_ENTER && keyEvent.getAction() == keyEvent.ACTION_DOWN){
            signUpOrLogIn(view);
        }
         return false;
    }

    @Override
    public void onClick(View view) {

        if(view.getId() == R.id.changeSignUpMode){

            if (signUpModeActive == true){

                signUpModeActive = false;
                changeSignUpModeTextView.setText("Sign Up");
                signUpButton.setText("Log In");

            }else{

                signUpModeActive = true;
                changeSignUpModeTextView.setText("Log In");
                signUpButton.setText("Sign Up");
            }

        }else if(view.getId() == R.id.logo || view.getId() == R.id.relativeLayout){

            InputMethodManager inm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            inm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(),0);

        }

    }


    public void signUpOrLogIn(View view) {

        showProgressDialog();
        String email = usernameField.getText().toString().trim();
        String password = passwordField.getText().toString().trim();

        if (signUpModeActive == true) {
            mAuth.createUserWithEmailAndPassword(email,password)
                    .addOnCompleteListener(MainActivity.this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {
                            hideProgressDialog();
                            Toast.makeText(MainActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
                            // If sign in fails, display a message to the user. If sign in succeeds
                            // the auth state listener will be notified and logic to handle the
                            // signed in user can be handled in the listener.
                            if (!task.isSuccessful()) {
                                Toast.makeText(MainActivity.this, "Authentication failed." + task.getException().toString().substring(task.getException().toString().indexOf(" ")),
                                        Toast.LENGTH_SHORT).show();
                                Log.i("Error", task.getException().toString());
                            } else {
                                onAuthSuccess(task.getResult().getUser());
                                showUserList();
                            }
                        }
                    });
        } else {
            mAuth.signInWithEmailAndPassword(email,password)
                    .addOnCompleteListener(MainActivity.this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {
                            hideProgressDialog();
                            // If sign in fails, display a message to the user. If sign in succeeds
                            // the auth state listener will be notified and logic to handle the
                            // signed in user can be handled in the listener.
                            if (!task.isSuccessful()) {
                                // there was an error

                                Toast.makeText(MainActivity.this, task.getException().toString(),
                                        Toast.LENGTH_LONG).show();
                            } else

                            {
                                onAuthSuccess(task.getResult().getUser());
                                showUserList();
                            }
                        }
                    });
        }
    }

    public void showUserList(){
        startActivity(new Intent(getApplicationContext(), UserList.class));
        finish();
    }
    private void onAuthSuccess(FirebaseUser user) {
        String username = usernameFromEmail(user.getEmail());

        // Write new user
        writeNewUser(user.getUid(), username, user.getEmail());

        // Go to MainActivity

    }
    private String usernameFromEmail(String email) {
        if (email.contains("@")) {
            return email.split("@")[0];
        } else {
            return email;
        }
    }

    private void writeNewUser(String userId, String name, String email) {
        User user = new User(name, email);

        mDatabase.child("users").child(userId).setValue(user);
        ArrayList<String> userNames = new ArrayList<>();
        userNames.add(name);
        mDatabase.child("usernamelist").setValue(userNames);
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mAuth = FirebaseAuth.getInstance();
        mDatabase = FirebaseDatabase.getInstance().getReference();


        if(mAuth.getCurrentUser()!=null){
            showUserList();
        }

        usernameField = (EditText) findViewById(R.id.username);
        passwordField = (EditText) findViewById(R.id.password);
        changeSignUpModeTextView = (TextView) findViewById(R.id.changeSignUpMode);
        signUpButton = (Button) findViewById(R.id.signupbutton);
        logo = (ImageView)findViewById(R.id.logo);
        relativeLayout= (RelativeLayout)findViewById(R.id.relativeLayout);

        signUpModeActive = true;

        changeSignUpModeTextView.setOnClickListener(this);

        usernameField.setOnKeyListener(this);
        passwordField.setOnKeyListener(this);

        logo.setOnClickListener(this);
        relativeLayout.setOnClickListener(this);



    }
}

UserList.java

public class UserList extends AppCompatActivity {

    private static final String TAG = "UserList" ;
    private DatabaseReference userlistReference;
    private ValueEventListener mUserListListener;
    ArrayList<String> usernamelist = new ArrayList<>();
    ArrayAdapter arrayAdapter;;

    ListView userListView;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_list);
        userlistReference = FirebaseDatabase.getInstance().getReference().child("usernamelist");
        onStart();
        userListView = (ListView) findViewById(R.id.userlistview);


    }

    @Override
    protected void onStart() {
        super.onStart();
        final ValueEventListener userListener = new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                usernamelist = new ArrayList<>((ArrayList) dataSnapshot.getValue());
                usernamelist.remove(usernameOfCurrentUser());
                Log.i(TAG, "onDataChange: "+usernamelist.toString());
                arrayAdapter = new ArrayAdapter(UserList.this,android.R.layout.simple_list_item_1,usernamelist);
                userListView.setAdapter(arrayAdapter);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w(TAG, "onCancelled: ",databaseError.toException());
                Toast.makeText(UserList.this, "Failed to load User list.",
                        Toast.LENGTH_SHORT).show();
            }
        };
        userlistReference.addValueEventListener(userListener);

        mUserListListener = userListener;
    }
    public String usernameOfCurrentUser()
    {
        String email = MainActivity.mAuth.getCurrentUser().getEmail();
        if (email.contains("@")) {
            return email.split("@")[0];
        } else {
            return email;
        }
    }
    @Override
    public void onStop() {
        super.onStop();

        // Remove post value event listener
        if (mUserListListener != null) {
            userlistReference.removeEventListener(mUserListListener);
        }

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()) {
            case R.id.action_logout:
                FirebaseAuth.getInstance().signOut();
                startActivity(new Intent(this, MainActivity.class));
                finish();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}
5

It's possible to use cloud function to fetch users list (view docs at firebase). Note, in the following example custom claims feature is used to check if user has enough privileges.

// USERS: return full users list for admin
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
import * as admin from 'firebase-admin'
import * as functions from 'firebase-functions'

export const listUsers = functions.https.onCall((data, context) => {
  // check if user is admin (true "admin" custom claim), return error if not
  const isAdmin = context.auth.token.admin === true
  if (!isAdmin) {
    return { error: `Unauthorized.` }
  }

  return admin
    .auth()
    .listUsers()
    .then((listUsersResult) => {
      // go through users array, and deconstruct user objects down to required fields
      const result = listUsersResult.users.map((user) => {
        const { uid, email, photoURL, displayName, disabled } = user
        return { uid, email, photoURL, displayName, disabled }
      })

      return { result }
    })
    .catch((error) => {
      return { error: 'Error listing users' }
    })
})
4

You can use Google Identity Toolkit API to get a list of all registered users in your Firebase project, this API is used by the Firebase CLI which can be accessed by running firebase auth:export results-file

Make sure Identity Toolkit API is enabled

firebase-users-list.js

const serviceAccount = require('path/to/firebase-sdk-json-service-account');

const googleapis = require('googleapis');
const identitytoolkit = googleapis.identitytoolkit('v3');

const authClient = new googleapis.auth.JWT(
    serviceAccount.client_email,
    null,
    serviceAccount.private_key,
    ['https://www.googleapis.com/auth/firebase'],
    null
);

authClient.authorize((err) => {
    if (err) {
        return console.error(err);
    }

    let nextPageToken = undefined;
    let users = [];
    const getAccounts = () => identitytoolkit.relyingparty.downloadAccount({
        auth: authClient,
        resource: {
            targetProjectId: serviceAccount.project_id,
            maxResults: 200,
            nextPageToken: nextPageToken
        }
    }, (e, results) => {
        if (e) {
            return console.error(err);
        }

        users = users.concat(results.users);
        if (results.nextPageToken) {
            nextPageToken = results.nextPageToken;
            return getAccounts();
        } else {
            console.log(users);
        }
    });
    getAccounts();
});
4

You can do it using admin.auth().listUsers

Here is the doc for this: https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth.html#listusers

And an usage example: https://firebase.google.com/docs/auth/admin/manage-users#list_all_users

function listAllUsers(nextPageToken) {
  // List batch of users, 1000 at a time.
  admin.auth().listUsers(1000, nextPageToken)
    .then(function(listUsersResult) {
      listUsersResult.users.forEach(function(userRecord) {
        console.log('user', userRecord.toJSON());
      });
      if (listUsersResult.pageToken) {
        // List next batch of users.
        listAllUsers(listUsersResult.pageToken);
      }
    })
    .catch(function(error) {
      console.log('Error listing users:', error);
    });
}
// Start listing users from the beginning, 1000 at a time.
listAllUsers();
6
  • 1
    Admin lib should not be used on client side?
    – BluePie
    Mar 11, 2021 at 2:05
  • Yes admin is only for server side (security reasons). But you may do an intermediate API if you need informations on client side.
    – Poyoman
    Mar 11, 2021 at 9:58
  • 1
    Good idea. Firestore still not allows to store user information inside users (which i find stupid :D ) So you will need to create a user list in firestore at one time ^^
    – Poyoman
    Mar 15, 2021 at 15:08
  • 1
    Note if you don't want to create an "API" you can still rely on firebase "functions"
    – Poyoman
    Mar 15, 2021 at 15:08
  • 1
    but if you use firebase "functions", you still have to authenticate requests (using something like jwt) right? or is there any way around it (it should be secure)? BTW im using realtime database, not firestore.
    – BluePie
    Mar 18, 2021 at 8:40
1

i will answer it simply as much as possible just add the registered user to your data base by using the following code

you can also use shared prefernces to save the data locally but it won't be able for other user.

once you save the list of user in the database simply retrieve it from there using adapters

FirebaseDatabase.getInstance().getReference().child("my_user")
                        .child(task.getResult().getUser().getUid())
                        .child("username").setValue(autoCompleteTextView1.getText().toString());
0

Users list in python:

from firebase_admin import credentials, db, auth
cred = credentials.Certificate('\path\to\serviceAccountKey.json')
default_app = firebase_admin.initialize_app(cred, {
    "databaseURL": "https://data_base_url.firebaseio.com"
})
users = auth.list_users()
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.