What is the best way to authenticate two types of users (Student and Driver) in my android app using Firebase [duplicate]

I am developing an Android app for my university transportation service (buses). It allows students to know where the bus is using maps. In indicates the location of the bus in a map(google map)

I have Two types of users (students, drivers)

Students and Drivers should first sign up (this is done using firebase authentication using email and password)

But the main problem is, Imagine following are the login credentials of a student;

**email: ** [email protected]

**password: ** 123456

Student can login using these credentials (after the sign up), and see the map.

Problem is, when I goto driver's login UI and enter the same credentials, it logs in the driver (which is supposed to login the student)

I know it is obvious that this happen since, it looks for any saved emails and matching password and log the user.

But I need an efficient way to check if it is really a student's login credentials or driver's login credentials.

Is there a way to send one more parameter to sign-in method along with the login credentials (email and password) in firebase, so I can pass a value for each user. (Imagine I pass a string value "student" when student is signing up and "driver" when a driver is signing up)

So I can retrieve that passed data and check if this credential is student's or driver's

Thank you so much!


Solution 1:

Firebase Authentication has no distinction between these types of users. All it does is determine whether the user is who they claim to be. Any distinction between the types of users will have to be made by your application after the user is authenticated.

You'd typically do this by storing the type for each user in a database, such as the Realtime Database or Cloud Firestore. In there you associate each user's UID with their type:

user_types:
  user1: "student"
  user2: "driver"
  user3: "student"
  user4: "student"

Alternatively you can store the user's type in their user profile with a custom claim. To set the custom claim using the Admin SDK for Node.js:

admin.auth().setCustomUserClaims(uid, {user_type: "driver"}).then(() => {
  // The new custom claims will propagate to the user's ID token the
  // next time a new one is issued.
});

Since this is a sensitive operation it can only be done through the Firebase Admin SDK, which you can't have in your app but can only be used in a trusted environment, such as your development machine, a server you control, or Cloud Functions.

Also see these previous questions about the topic:

  • How can handle separate login for two types of users in same firebase app?
  • Different permissions Firebase Auth
  • How to log in two different types of users to different activities automatically without having to log in again?
  • How do i differentiate between different level of users in firebaseAuth
  • How to separate two different user in firebase android app?

Solution 2:

You should use firebase database as well. When your Sign-Up is a success, make a record of users in the firebase Database. Add type = "students" or "driver" in every record. By this way you can check the type of login and modify it according to your needs.

Something Like this during login:

/**
     * Login with firebase credentials
     */
    private void loginFirebase() {
        progressDialog();
        FirebaseAuth.getInstance().signInWithEmailAndPassword(emailEt.getText().toString().trim(),
                passwordEt.getText().toString().trim())
                .addOnCompleteListener(LoginActivity.this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (!task.isSuccessful()) {
                            dismissDialog();
                            Toast.makeText(LoginActivity.this, "Login failed: "
                                            + UtilMethods.firebaseAuthFailMessage(task),
                                    Toast.LENGTH_SHORT).show();
                        } else {
                            verifyUserType();
                        }
                    }
                });
    }

    /**
     * Verify if user type is customer or business.
     * If type is customer then allow login else Alert the user
     */
    private void verifyUserType() {
        DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference(Constants.FIREBASE_NODE_USER_DETAILS);
        dbRef.child(FirebaseAuth.getInstance().getUid()).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                String userType = dataSnapshot.child("type").getValue(String.class);
                if (userType != null && userType.equals("customer")) {
                    //checkIfEmailVerified();
                } else {
                    dismissDialog();
                    Toast.makeText(LoginActivity.this, "You are not authorized to access this application!",
                            Toast.LENGTH_SHORT).show();
                    FirebaseAuth.getInstance().signOut();
                }

            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {
                dismissDialog();
                Toast.makeText(LoginActivity.this, "" + databaseError.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });

    }

Here is the snapshot: Users DB Snapshot

Here is the SignUp Process:

private void signUpMethod() {
        progressDialog();
        final String email = emailEt.getText().toString().trim();
        final String password = passwordEt.getText().toString().trim();
        //authenticate user
        firebaseAuth.createUserWithEmailAndPassword(email, password)
                .addOnCompleteListener(SignUpActivity.this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        // 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()) {
                            dismissDialog();
                            // there was an error
                            Toast.makeText(SignUpActivity.this, "" + task.getException().getMessage(),
                                    Toast.LENGTH_SHORT).show();
                        } else {
                            addUserDetailsToDatabase(task.getResult().getUser());
                        }
                    }
                });
    }

    private void addUserDetailsToDatabase(FirebaseUser user) {

        DatabaseReference databaseReferenceUsers = firebaseDatabase.getReference("users").child(user.getUid());

        Users usersDetails = new Users();
        usersDetails.setName(storeFullNameEt.getText().toString());
        usersDetails.setMobile(mobileEt.getText().toString());
        usersDetails.setEmail(user.getEmail());
        usersDetails.setAddress(addressEt.getText().toString());
        usersDetails.setCity(cityEt.getText().toString());
        usersDetails.setState(stateEt.getText().toString());
        usersDetails.setPinCode(pinCodeEt.getText().toString());
        usersDetails.setCustomerUId(user.getUid());

        databaseReferenceUsers.setValue(usersDetails).addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                dismissDialog();
                firebaseAuth.signOut();
                finish();
            }
        });

    }

And This is your model class, create fields according to your needs:

@IgnoreExtraProperties
public class Users {

    private String name;
    private String mobile;
    private String email;
    private String address;
    private String city;
    private String state;
    private String pinCode;
    private String customerUId;

    public Users() {
        name = "";
        mobile = "";
        email = "";
        address = "";
        city = "";
        state = "";
        pinCode = "";
        customerUId = "";
    }

    @PropertyName("name")
    public String getName() {
        return name;
    }

    @PropertyName("name")
    public void setName(String name) {
        this.name = name;
    }

    @PropertyName("mobile")
    public String getMobile() {
        return mobile;
    }

    @PropertyName("mobile")
    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    @PropertyName("email")
    public String getEmail() {
        return email;
    }

    @PropertyName("email")
    public void setEmail(String email) {
        this.email = email;
    }

    @PropertyName("address")
    public String getAddress() {
        return address;
    }

    @PropertyName("address")
    public void setAddress(String address) {
        this.address = address;
    }

    @PropertyName("city")
    public String getCity() {
        return city;
    }

    @PropertyName("city")
    public void setCity(String city) {
        this.city = city;
    }

    @PropertyName("state")
    public String getState() {
        return state;
    }

    @PropertyName("state")
    public void setState(String state) {
        this.state = state;
    }

    @PropertyName("pinCode")
    public String getPinCode() {
        return pinCode;
    }

    @PropertyName("pinCode")
    public void setPinCode(String pinCode) {
        this.pinCode = pinCode;
    }

    @PropertyName("customerUId")
    public String getCustomerUId() {
        return customerUId;
    }

    @PropertyName("customerUId")
    public void setCustomerUId(String customerUId) {
        this.customerUId = customerUId;
    }
}

Solution 3:

I don't know if there's an official or standard way to do this with Firebase but if that's not the case what I would do is to store the type of user in the database and then check the information before login. The logic would be the following:

  1. Get the type of user given an email
  2. Check if the type returned matches the login screen type
  3. Do the login if the type matches, show some error otherwise

I hope this helps.

Solution 4:

I have the same approach on one of my developed app , and what i did it's just adding a boolean type to the user true if it's a driver and false if it's a student , and you have to handle this credential from the sign up . So when sign in , you will get the type of the user !