I have integrated firebase auth with my android app. Lets say a user has a mail abc#abc.com. I want to add some extra information to the user like the name of the user, occupation and address. How can i connect the user auth table with my android app to do that?
Do i need to write any APIs for that?
First, create a users directory in db. Then, using user's unique id you get from authn process, store the user info under users/{userid}.
To achieve this, you need to get into the details of Firebase database. See here: https://firebase.google.com/docs/database/android/save-data
You do not need to write any custom code to do this. Firebase already has features you can use.
The first thing you'd need to do is ensure that users have access to only the data they store. To do this, go to Database/Rules and change your rules to this:
{
"rules": {
"my_app_user": {
"$uid": {
".write": "auth != null && auth.uid == $uid",
".read": "auth != null && auth.uid == $uid"
}
}
}
}
Then, to save the new details in a Firebase database, do this:
MyAppUser user = new MyAppUser();
user.setAddressTwo("address_two");
user.setPhoneOne("phone_one");
...
mDatabaseReference.child("my_app_user").child(firebaseUser.getUid()).setValue(user).
addOnCompleteListener(DetailsCaptureActivity.this,
new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
...
The name of the child my_app_user must match both in your code and the Firebase rules else it won't persist.
If everything goes as is supposed to, you should see the details in your database:
You have to create another database table say "user". On successful signin, signup for first time you have to create a new row in user table.
public static void writeNewUser(DatabaseReference databaseReference, String userId, String name, String email, int accountType) {
User user = new User(name, email, accountType);
databaseReference.child("users").child(userId).setValue(user);
}
You may refer https://github.com/firebase/quickstart-android/tree/61f8eb53020e38b1fdc5aaeddac2379b25240f3b/database
Related
I previously asked question to secure realtime database on firebase. I am only using Firebase Realtime database just to creating chat app. The user verification working separately on our own server and we are not using any firebase auth service for user verification. As Frank van Puffelen suggested few official docs. I am now generating JWT to authorize as per documentation but as we are not using any other services of firebase i am not sure how to authorized the real time database with generated JWT.
mAuth.signInWithCustomToken(mCustomToken)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// Sign in success
} else {
// If sign in fails
Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
}
}
});
How to validate users and secure our database from world so only app user can edit their node only.
I followed this guide for
Authenticate with Firebase with custom token.
User login with their credential
Server generate custom token (JWT).
Pass it to signInWithCustomToken as per doc.
What after that? guide bit incomplete for my use case.
Edit: The process:
Server generates JWT With PHP Firebase JWT
$Token = JWT::encode($request_data,$secret_Key,'HS512');
this token return back to app if user login successfully.
After successfully user login i call sign in with custom token i received from server with firebase
firebaseAuth = FirebaseAuth.getInstance();
firebaseAuth.signInWithCustomToken(Session.getJWT())
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isComplete()){
Intent intent=new Intent(getActivity(),MainActivity.class);
getActivity().startActivity(intent);
}
}
});
When user click chat button. Check if room already exist or not if not then create one for 2 users with their phone numbers like 9810012345-9810012346
DatabaseReference db = rebaseDatabase.getInstance().getReference();
db.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild(RoomTitle)) {
RoomName(RoomTitle, true);
}else {
RoomName(RoomTitle, false);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
public void RoomName(String Name, boolean RoomExist) {
button_SendMessage.setEnabled(true);
if (!RoomExist) {
Log.d(TAG, "Room Not Exist Creating One);
RoomName.put(Name, "");
FireBaseDatabase.updateChildren(RoomName);
}
// Launch Chat Screen
}
Then on chat screen i add items like linked question database structure
databaseReference = FirebaseDatabase.getInstance().getReference().child(Room_Name);
So creating room,allow reading writing message only created room, block access if room doesn't belong to users. I need to set rules for Realtime Database and only app users can access their rooms not others even they are app users(Block others app users to sneak into others users rooms) Below is the sample of our Realtime Database structure for better understanding how our 2 user room look like. I am not sure there is much thing to do on app side, i feel it's more database than app code question.
Once your call to signInWithCustomToken succeeds, that token will be passed to the server whenever the Firebase Realtime Database SDK connects, and from there on it will be verified and passed on to the auth variable in your security rules.
So you can check if the request comes from a signed-in user with:
{
"rules": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
That's a bit broad though, so you'll want to narrow it down to specific users. For example, you can allow only a content-owner access with:
{
"rules": {
"some_path": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth !== null && auth.uid === $uid",
".write": "auth !== null && auth.uid === $uid"
}
}
}
}
Any claims you have in your JWT will be available in the security rules too under the auth.token variable.
I have developed an app using firebase realtime database. In the app, if e-g user 1 clicks on the profile of user 2 then the data of user 2 would be changed. User 1 can only change the data of other users if he clicks on their profiles. I have written some rules to secure my database but these rules won't allow user 1 to change the data of other users if he clicks on their profile. You help will be highly appreciated. Thank You
Below is my code:
Firebase Rules
Database Structure
Java Code which will change user data if his profile is clicked
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dRef.child(modelClass.get(position).userID).child("showGigCount").setValue(modelClass.get(position).getShowGigCount()-1); // this will decrease showGigCount for clicked users
dRef.child(modelClass.get(position).getUserID()).child("clicksOnProfile").setValue(modelClass.get(position).getClicksOnProfile()+1); // this will increase clicksOnProfile for clicked users
dRef.child(modelClass.get(position).getUserID()).child("lifeTimeClicksOnProfile").setValue(modelClass.get(position).getLifeTimeClicksOnProfile()+1); // this will increase clicksOnProfile for clicked users
It sounds like you want to allow certain properties to be modified by all users, which you can do with:
...
"$user_id": {
".write": "auth != null && $user_id === auth.uid",
"showGigCount": {
".write": "auth != null"
},
"clicksOnProfile": {
".write": "auth != null"
},
"lifeTimeClicksOnProfile": {
".write": "auth != null"
},
}
...
The added rules give permission to write the lower level properties, while your original write rules on $user_id still rejects writing other properties of the user.
I want to make public only username node under the user's child for register function. So this value must be able for the non-register users to register. Here is my firebase database structure. How can I do that?
Here are my rules
{
"rules": {
"Homeland": {
".indexOn": ["username","email","bakiyetl","yarismada","yarismadabb","splashmesaj","uygulama1tut","uygulama2tut","uygulama3tut","uygulama4tut","uygulama5tut","uygulama6tut","uygulama7tut","uygulama8tut","uygulama9tut","uygulama10tut"]
},
"gunluksifreler": {
".read": true, // <-- allows every person
".write": true
},
".read": "auth !== null", // <-- allows read if logged in
".write": "auth !== null" // <-- allows write if logged in
}
}
Search username in database.
Query cmyquery = refbir.child("Homeland").orderByChild("username").equalTo(usergivenname);
cmyquery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
//user name already taken
}else if(sonlandirgorev!=1){
//You can use this username
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Rule 1: To be able to read a location or run a query on a location, you must be able to read the data on that location.
Knowing that, let's look at:
Query cmyquery = refbir.child("Homeland").orderByChild("username")
This code requires that the user can read the Homeland node.
This is referred to in the documentation as rules are not filters.
Rule 2: One you can read or write data at a certain level in the JSON, that permission can't be taken away at a lower level.
Given this rule and the above: one a user can read and query Homeland they can read all data below it. There is no way to hide part of that data.
This is referred to in the documentation as read and write rules cascade.
The common solution is to split the data by who needs access to it. So if you want only the username property values to be available to everyone, create a top-level usernames node with the same keys under it, and then just the value of that user's user name. On that new usernames node you can then grant more liberal access than on the Homeland node.
I want to allow access to user name so other users can search uses by user name.
I have a search feature in my app that allows users to search other users by user name
Firebase Rules
{
"rules": {
"users": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth.uid != null",
".write": "auth.uid != null"
},
},
"chat": {
"messages": {
".write": true,
".read": true
}
},
"app-settings": {
".write": true,
".read": true
}
}
}
Here is JSON of users
{
"app-settings" : {
"app-Available" : true,
"version" : "4"
},
"users" : {
"uid" : {
"blocked" : false,
"email" : "gamatiaihab#gmail.com",
"profilePhotoUrl" : "https://lh3.googleusercontent.com/a-/AOh14Gi6eXrdLfZTQH0B7GvoTxhqBHoVFUUTibK3QKfrfA=s96-c",
"uid" : "uid",
"userName" : "gamatiaihab"
}
}
}
In my app, I have a feature that allows the user to change their user name, with this code I'm trying to validate the user name checking if it's takin by other user or not, I normally access the single user information by child(uid) this works if firebase rules are only configured for authenticated users, but in order to validate the user name I need to not order the by child(uid) because this will return only single user which is the current user, I need to order by child("users").orderBy("userName") and this returns PERMISSION DENIED because i didn't pass child(uid)
private void validateUserName(final String chatUserName){
mEditChatUserNamePr.setVisibility(View.VISIBLE);
mDb = FirebaseDatabase.getInstance().getReference().child("users");
mDb.orderByChild("userName")
.equalTo(chatUserName)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null){
mEditChatUserNamePr.setVisibility(View.GONE);
mChatUserNameInput.setError("User name not available");
}else {
updateUserName(chatUserName);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
A user either has access to a complete node, or they don't have access to the node at all. There is no way to give them access to only part of each child node.
But even if there was, your code would have a problem: another user might claim the name between the time your query runs, and you write the new user name to the database. And while this problem may seem unlikely in your testing, in a successful app this type of problems (known as a race condition) is guaranteed to come back and bite you.
The idiomatic (and only guaranteed) way to implement uniqueness is to use the thing that must be unique as the keys in a list in the database. So in your case that'd mean:
Creating a list of usernames, with each key being a username, and each value being the UID of the user with that username.
Using a transaction to ensure no two users are updating the same node at the same time.
Using security rules to ensure that nobody can overwrite a username that was claimed by another user already.
Instead of repeating more here, let me point you to some previous questions where this was covered in more detail:
Firebase android : make username unique
How do you prevent duplicate user properties in Firebase?
unique property in Firebase
Firebase security rules to check unique value of a child #AskFirebase
I'm make an app with a Firebase Auth, but when I delete or when I disable an account I need make a signOut() manually (I control this with a user reload), if I don't, the user can keep uploading data. How I can fix this without the app code?
Firebase rules
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}
App Code - How I detect it
if(user != null) user.reload().addOnCompleteListener(this, new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(!task.isSuccessful()) {
String exc = task.getException().getMessage();
Log.e("FireBaseUser", exc);
auth.signOut();
}
}
});
When a token is minted, it gets an expiration timestamp. This essentially says: "the information in this token is valid until ...". Deleting the user does not invalidate any existing tokens.
Keep in mind that since the newest Firebase Authentication SDKs, the tokens are only valid for one hour. So after at most an hour, the token will expire and it will be impossible for the deleted user to refresh it.
If this is not enough for your application, you can add logic to your application that marks the deleted users in the database (in a section that only the administrator can access):
/deletedUsers
209103: true
37370493: true
You can then in your security rules validate that only non-deleted users can access data:
".read": "!root.child('deletedUsers').child(auth.uid).exists()"