I'm starting a new project and Firebase Auth was the choice for authentication. The idea is to create/login users through Firebase Auth and then, use the Firebase ID Token to authenticate on my backend (through Authentication header).
In Google Samples, this is the way I should get the token:
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});
But, as you can see, this is a async call, because it goes to Firebase servers to get me the Token. So, every REST API call to my backend, I need to run the above code, because I don't know when the token has expired.
Is there a better way to safety call my backend REST APIs using Firebase Auth? Or using the Firebase ID Token is the best one? If so, how should I wrap this id token get for every REST API call?
If you have a better way to authenticate users to call rest apis later, I'm all ears.
so the Idea is quite simple. You can use this method in the Android device as you already know:
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});
Once you hold the instance of the token you send it to your backend for authentication there, it will authenticate only once and send you backend a token that is managed by the backend itself. That's the token that will be sent in each subsequent call to the backend, not the generated by the above method.
Related
I am using Firebase FCM to send notifications from my server to the users.
When the user installs the App for the first time, i catch the fresh and new token at MessagingService.java:
#Override
public void onNewToken(#NonNull String tkn) {
super.onNewToken(tkn);
sendTokenToServer(tkn);
}
Here comes the problem, when the user closes session (without uninstalling the app), SharedPreferences are deleted. A new session is started; but onNewToken() is not called. So, i must manually retrieve the Token inside my MainActivity in order to send it to the server. I am getting the updated token with this piece of code:
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(MainActivity.this, new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
sendTokenToServer(instanceIdResult.getToken());
}
});
As you know, that code is deprecated and should be avoided. Instead, i tried to replace it with this piece of code with no success:
FirebaseInstallations.getInstance().getToken(true).addOnCompleteListener(new OnCompleteListener<InstallationTokenResult>() {
#Override
public void onComplete(#NonNull Task<InstallationTokenResult> task) {
if(task.isSuccessful()) {
String token = task.getResult().getToken();
}
}
});
The Token length obtained at onNewToken() is 163.
The token length obtained at deprecated call is 163 (perfect, but deprtecated).
The token length obtained at FirebaseInstallations is 316.
My firebase API at server side fails to send a notification using the code of 316 length.
Any one knows what i am doing wrong? Or why i get those different length tokens?
Update:
Server side python, retrieves token from database and sends the notification like this. Please note this code is working when token len is 163.
from pyfcm import FCMNotification
push_service = FCMNotification(api_key=" ... ")
push_service.notify_single_device(registration_id=token, data_message=datamessage, time_to_live=1296000)
When trying to send a notification with long token this is the message I get:
{'multicast_ids': [8149274412512777031], 'success': 0, 'failure': 1, 'canonical_ids': 0, 'results': [{'error': 'InvalidRegistration'}], 'topic_message_id': None}
From the documentation for FirebaseInstanceId:
This class is deprecated. Firebase Instance ID has been replaced with
FirebaseInstallations for app instance identifiers and
FirebaseMessaging.getToken() for FCM registration tokens.
Looks like you need FirebaseMessaging.getToken() not FirebaseInstallations.getInstance().getToken(true) as you want a FCM registration token.
These APIs provide different tokens for different purposes.
So in your example it would be:
FirebaseMessaging.getInstance()
.getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override public void onComplete(#NonNull Task<String> token) {
}
}
);
I'm using Firebase auth to login users to my webapp and android app.
The flow for the webapp lets me log the user in from the client, then pass the Firebase token to my server where I verify with Firebase before adding various user info to my database.
I'm now trying the same thing for Android, but am having some problems getting the token.
Here is the login code:
// Initialize Firebase Auth
mAuth = FirebaseAuth.getInstance();
// ...
mAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener((MainActivity) context, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
// ***I want to get the token here***
FirebaseUser fbUser = task.getResult().getUser();
// send user details and token to server
} else {
// If sign in fails, display a message to the user.
}
}
}
});
Elsewhere, I see that in the Firebase docs, there is this snippet that gets the Task<GetTokenResult> , which is what I want, but I can't seem to get this in the createUserWithEmailAndPassword method.
From the firebase docs
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
public void onComplete(#NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
String idToken = task.getResult().getToken();
// Send token to your backend via HTTPS
// ...
} else {
// Handle error -> task.getException();
}
}
});
How can I get the token in createUserWithEmailAndPassword?
You can use your second bit of code inside the first bit, after the sign-in completes.
// ***I want to get the token here***
FirebaseUser fbUser = task.getResult().getUser();
fbUser.getIdToken(true)
.addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
// ...
}
I have integrated firebase as a backend in my android app.I am trying to change users device id every time app opens.
I am using below code to get firebase registration id:
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
// Get Instance ID token
String token = task.getResult().getToken();
Toast.makeText(MainActivity.this, token, Toast.LENGTH_SHORT).show();
}
});
How can I change this token every time users open an app.
Any help would be appreciated.
THANKS
The registration token may change when:
The app deletes Instance ID
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
Read the documentation here
You can revoke the token from server and notify the device.
The procedure is well explained here.
I am developing an app, and so far it's able to upload images, and register users.
However, these two functionalities run independent of each other. Ergo, I need to make it so that the images are saved under the user that uploads it. I am a novice Android programmer and just started learning about Firebase and could use the help.
In Registration process,
FirebaseAuth.getInstance()
.createUserWithEmailAndPassword(email, email)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
android.util.Log.e("Firebase", "performFirebaseRegistration:onComplete:" + task.isSuccessful());
// 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()) {
AlertUtils.showAlert(MainActivity.this, getString(R.string.sign_up), task.getException().getMessage());
} else {
FirebaseUser firebaseUser = task.getResult().getUser(); // here you will get userDetails
}
}
});
From firebaseUser you can get user id by firebaseUser.getUid().
Once you upload the message,sent to realtime firebase b the user id as below,
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
database.child(ARG_USERS)
.child(firebaseUser.getUid())
.child("image")
.setValue(<you image download url>);
I knew that we can verify the users email with Firebase Auth 3.0. I'm not able to find any documentation regarding email verification on Android. I'm able to find the same for iOS as well as web but not for Android. Any link to the documentation would be helpful.
From the image, it is clear that once the user signs in, he will be intimated regarding that on email to confirm his subscription. I've subscribed myself and also verified in the users section in Auth tab and I am able to see my mail id and firebase generated unique user id. What's missing here is the confirmation email to my email id. Did some one try this or am I too early trying this? Thanks for your help.
Email verification for android is now available in Firebase.
See this release note:
https://firebase.google.com/support/release-notes/android#9.6
Update
Email verification is available in version 9.6 and higher of the Firebase SDK for Android.
Original answer
Email verification is not available for Android yet. Also answered here with more context.
An alternative suggested by the Firebase team
One thing you could do is to add a node to your Firebase Database which contains all email addresses as children. You should make this node only publicly readable (via Firebase security rules).
Then from within your apps, once a user signs up / signs in, you check if the email of that user is on the list, and if not, you sign them out and kick them out of your app (and as a bonus, you could even log the intruder's email address in your database, so you can later check who is trying to access your app).
This will work for initial testing if you know the e-mail ids of the people who are gonna test your app until the e-mail verification makes its way to Android.
Since email verification only works with Email/Password authentication, the best place to send it wold be in the onComplete method of createUserWithEmailAndPassword(...) method, after signup is successful.
firebaseAuth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
sendVerificationEmail();
....
The custom sendVerification method is:
public void sendVerificationEmail() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
user.sendEmailVerification()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(SignUpActivity.this, "Signup successful.
Verification email sent", Toast.LENGTH_SHORT).show();
}
}
});
}
}
You can then check if the user has verified their email anywhere in your app by calling:
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
firebaseUser = firebaseAuth.getCurrentUser();
if (firebaseUser != null ) {
Log.e(TAG, firebaseUser.isEmailVerified() ? "User is signed in and email is verified" : "Email is not verified");
} else {
Log.e(TAG, "onAuthStateChanged:signed_out");
}
}
};