got some copy-paste code from firebaseauth tutorial to connect a client on my app with Microsoft authentication. problem is, login screen not showing
you can find the full tutorial here.
note, I did copy everything just to test connection (not including optional code, to simplify things)
the problem stats at firebaseAuth.startActivityForSignInWithProvider method. it always ends up with failure. trace show this message:
"FirebaseAuthException... There was an error while trying to get your package certificate hash."
I did everything in the tutorial including registration of my app at Microsoft and Firebase Authentication screen. I ran this code at android studio emulator and an actual device, same result
my sign in function:
public void signinToMicrosoft(Activity activity) {
OAuthProvider.Builder provider = OAuthProvider.newBuilder("microsoft.com");
Log.e(TAG,"Signing with microsoft");
Task<AuthResult> pendingResultTask = firebaseAuth.getPendingAuthResult();
if (pendingResultTask != null) {
// There's something already here! Finish the sign-in for your user.
pendingResultTask
.addOnSuccessListener(
new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
Log.e(TAG,"Pending Success");
// User is signed in.
// IdP data available in
// authResult.getAdditionalUserInfo().getProfile().
// The OAuth access token can also be retrieved:
// authResult.getCredential().getAccessToken().
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG,"Pending Failed: "+e.getMessage());
// Handle failure.
}
});
} else {
Log.e(TAG,"No Pending");
// There's no pending result so you need to start the sign-in flow.
// See below.
}
firebaseAuth
.startActivityForSignInWithProvider(activity, provider.build())
.addOnSuccessListener(
new OnSuccessListener<AuthResult>() {
#Override
public void onSuccess(AuthResult authResult) {
Log.e(TAG,"Auth Success");
// User is signed in.
// IdP data available in
// authResult.getAdditionalUserInfo().getProfile().
// The OAuth access token can also be retrieved:
// authResult.getCredential().getAccessToken().
}
})
.addOnFailureListener(
new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG,"Auth Failed: "+e.getMessage() + "\nTrace: "+ e.getClass().getCanonicalName());
// Handle failure.
}
});
}
a custom chrome tab was supposed to open and allow signing to Microsoft but it pops up for a split second and closes. if anyone had that problem or got a fix for me it would be much appreciated. thanks!
If anyone still has this problem, I just want to share my solution and my problem which is similar to this.
TL;DR
Your SHA-1 Fingerprint may be used by another Firebase project so either delete that fingerprint or sign with a different keystore
Long Version
I worked on a project that has a development and production environment using different Firebase projects. We use Firebase Auth to link Microsoft login for our Android app. I got the same error as above while trying to set up the development environment of the project. We used to only have one environment for Firebase so this was never a problem.
It turns out that when you don't provide an SHA-1 fingerprint when you create the project, Firebase automatically adds them when you run an authentication call. This meant that when we created debug APKs for testing, the SHA-1 fingerprint was recorded to the Firebase project that was intended for the live environment so when you try to add the same fingerprint in another project it won't let you. The solution would be to include the SHA-1 fingerprint in the development environment but to do so you would need to delete it the fingerprint from the live environment (in my case) and wait for that change to reflect. Or you could sign with a different, unused keystore.
You need to have microsoft (hotmail, outlook ...) account on your android, to solve this problem.
Approaching to the final stage of the authentification, but something is going wrong in handleSignInResult method. It returns Exception code 10 (Developer error) in logs. Google provides comprehensive description:
The application is misconfigured. This error is not recoverable and will be treated as fatal. The developer is an idiot...
What should I do to handle this (get an account) and finally retrive values from account?
Thank you in advance for your help!!!
MainActivity:
package ru.podgorny.carcall;
import ...
public class MainActivity extends AppCompatActivity {
SignInButton signInButton;
public static final int RC_SIGN_IN = 07;
public static final String TAG = "MainActivity";
TextView tw1;
TextView tw2;
GoogleSignInOptions gso;
GoogleSignInClient mGSC;
#Override
protected void onCreate (Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "Activity Works");
findViews();
gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
//.requestProfile()
.build();
mGSC = GoogleSignIn.getClient(this, gso); //smth with mGSC variable....
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
onClick2(v);
}
};
signInButton.setOnClickListener(onClickListener);
}
private void findViews() {
Log.d (TAG, "findViews started");
signInButton = findViewById(R.id.idButtonGoogle);
tw1 = findViewById(R.id.textView1);
tw1 = findViewById(R.id.textView2);
Log.d(TAG, "Views finded");
}
public void onClick2(View view) {
Log.d(TAG, "onClick started");
switch (view.getId()) {
case R.id.idButtonGoogle:
signIn();
break;
}
Log.d(TAG, "OnClick Started");
}
public void signIn() {
Intent signInIntent = mGSC.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
Log.d(TAG, "startActivityForResult works");
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "OnActivityResult started");
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
Log.d(TAG, "TASK started");
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
handleSignInResult(task);
Log.d(TAG, "OnActivityResult returned");
}
}
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);//ERROR -- Code 10
Log.d(TAG, "Account received");
updateUI(account);
Log.d(TAG, "updateUI Launched");
} catch (ApiException e) {
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
updateUI(null);
}
}
private void updateUI(GoogleSignInAccount account) {
if (account!=null) {
tw1.setText("OK");
tw2.setText("Name: " + account.getGivenName() + ", Family name: " + account.getFamilyName() + ", Email: " + account.getEmail() /*+ " image: " +
account.getPhotoUrl()*/);
}else {
tw1.setText("SMTH wrong");
}
}
}
This error might happen if you are not using same project at console.developers.google and console.firebase.google.com. If project is same at both console make sure you have add your SHA1 Key properly. Get SHA1 from Android studio.
Open Android Studio
Open your Project
Click on Gradle (From Right Side Panel, you will see Gradle Bar)
Click on Refresh (Click on Refresh from Gradle Bar, you will see List Gradle scripts of your Project)
Click on Your Project (Your Project Name form List (root))
Click on Tasks
Click on Android
Double Click on signingReport (You will get SHA1 and MD5 in Run Bar(Sometimes it will be in Gradle Console))
Select app module from module selection dropdown to run or debug your application
You also need to get google-services.json from firebase console and put into your project.
I landed into the same problem and wasted hours. On digging deeper into OAuth and OpenId, I figured out the reason. We are doing a conceptual error here.
For android or any other platform (except web), you need to create at least two types of client id in the same project of google API console. These Client ID types are:
Web Application
Android
You can create them in any order. While creating Android type Client Id, you need to give package name and SHA1. While creating Web Application Id, you just need to give a name.
You don't need to do anything with any of these id's further until you want to verify the user at your backend. In other words, if you want your backend server to ask google server about this user's information, then only you would need Web Application Id. The conceptual flow is as follows:
First send Web Application Client Id from Android App to Google Sign-in Server as an additional option using requestIdToken(your_web_app_client_id).
You will get back a token in Android app upon user's sign in.
Send this token to your backend.
Now your backend can exchange this token with Google Servers to get user's information
Send this Web Appplication Client Id from Android App to backend server.
Use this Web Application Id if you want to verify user at your backend.
The answer for me was that you actually need to combine the two main answers given here:
Make sure that you created Google OAuth client ids for Android (one for Debug and one for release) and then assure that they have assigned the right SHA1 as described in the accepted answer.
Then you also need to create an OAuth client ID for Web and use that one for the actual SignIn:
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(WEB_CLIENT_ID)
.requestEmail()
.build();
I fixed this problem by this way
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.AUTH_ID))
.requestEmail()
.build();
where my AUTH_ID is
I've found another source of the problem.
In my case the keys were alright, but applicationId field in build.gradle script differed from app's package name.
Small research showed that applicationId field value takes some kind of "precedence" before app's package name conserning Google autentication.
After commenting applicationId line in build.gradle, app autenticates itself in Google by package name.
Another source of this error is adding applicationIdSuffix to your Build Variants (Flavors) in the gradle file. If you had everything working and suddenly when adding flavors the Google Sign In broke, check this configuration variable.
The applicationIdSuffix parameter might require a unique certificate for each suffix. I simply removed it because I didn't need to deploy different products or releases yet. Also, you can set the same configuration for each flavor programmatically.
Configure certificates build types: Force to use same certificate to sign different "buildTypes" that are configured for a particular "productFlavor"?
Option: then keep in mind that google also signs the app with the another certificate. So, you need to add the 2nd fingerprints as well.
Otherwise, you will receive this error.
I paste the release keystore sha1 to google console, but forget add debug config !!
This solution assumes that the root cause of your problem is that you are debugging and in that case the fingerprints of the app are different than the final production builds. To over come that:
Add your debug.keystore's SHA1 and SHA256 fingerprint to your Firebase project with these steps:
Obtain the debug.keystore's fingerprints: Linux/Mac - keytool -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore, Windows - keytool -list -v -alias androiddebugkey -keystore %USERPROFILE%\.android\debug.keystore
Add these fingerprint's to your Firebases project's Android app section: https://support.google.com/firebase/answer/9137403?hl=en
This Problem can be solved by using WebApplication ID and android Client ID
When ever you configure the project to generate id for android app , it generates 2 types of ids 1 Android 2 WebApplication ,
We need to use 2nd one (web oAuth id) and not the 1st one , it will be resolving your issue
I would like to add Supplemental Information as to Why #Patrick R answer (above works/marked as correct). To execute your project/practice, Google Console needs to ID your app via SHA-1 key when its distributed on Google Play Market, However, when your are simply experimenting with Login confirmation and Proof Of Concept, then it associates the debug SHA-1 key (your app automatically generates this) for this exact purpose, keeping your testing and production changes modular.
Had same issue. Code 10 in signed apk. I put all the four keys from Google Play Console (Setup -> App integrity -> Play App Signing) to Firebase project and pasted new Google-services.json in app folder in Android Studio and then after generating Signed Apk, Google sign in worked.
Make sure you use Web Client ID from https://console.cloud.google.com and not Android client.
Even if it is mentioned Web application in Type column:
enter image description here
Try adding .requestIdToken(getString(R.string.default_web_client_id)).
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id)) //add this line
.requestEmail()
.build();
atleast on the debug version, i didnt send any token and it worked...
ie,no 'requestIdToken' in GoogleSigninOptions.build()
It may not work in Release...will try ..
I had the same issue and non of the answers above worked for me:
If you get error code 10 that means for sure that you have a SHA problem. My solution was to go to the Firebase project, Settings Overview (top left cornet) -> Click on the Settings icon -> Project Settings. There, General tab will be first selected and you have to scroll down to SDK setup and configuration, select the Android app and make sure you enter the same SHA1/256 key that you've entered on the Google Cloud Platform when you've configured your OAuth consent screen and the credentials.
Hope this helps you too. Cheers!
Press "Sync Project with Gradle files."
I am looking for firebase support for my application. I have a web client talking with my server side Java components using rest calls. I want to give my users ability to login using any social media profiles. I have read java support for firebase here:
Firebase user Authentication
I have created a firebase profile & a project under it.
Under that project I have enabled email / password authentication.
Then I have used the following code to create a dummy user.
Firebase ref = new Firebase("https://myappname.firebaseio.com");
ref.createUser("bobtony # firebase.com", "correcthorsebatterystaple", new Firebase.ValueResultHandler<Map<String, Object>>() {
#Override
public void onSuccess(Map<String, Object> result) {
System.out.println("Successfully created user account with uid: " + result.get("uid"));
}
#Override
public void onError(FirebaseError firebaseError) {
// there was an error
}
});
Code runs fine, no exceptions - but this code did not create a new user in firebase.
What did I miss? Did I need to do anything extra for this code to be able create a firebase user?
I am thinking about keeping all registration ids(push token) in DB and sending notifications to user from iPhone. I tried something like this but did not get any notification.
func sendPNMessage() {
FIRMessaging.messaging().sendMessage(
["body": "hey"],
to: TOKEN_ID,
withMessageID: "1",
timeToLive: 108)
}
What I am doing wrong or maybe it is impossible at all?
Currently it's not possible to send messages from the application itself.
You can send messages from the Firebase Web Console, or from a custom server using the server-side APIs.
What you might want to do is to contact a server (like via http call) and that server will send the message to the user.
This way ensure that the API-KEY of the server is protected.
PS: the sendMessage(..) api is called upstream feature, and can be used to send messages from your app to your server, if you server has an XMPP connection with the FCM server.
Yes you can send push notification through Firebase.Please make sure do NOT include the server-key into your client. There are ways "for not so great people" to find it and do stuff... The Proper way to achieve that is for your client to instruct your app-server to send the notification.
You have to send a HTTP-Post to the Google-API-Endpoint.
You need the following headers:
Content-Type: application/json
Authorization: key={your_server_key}
You can obtain your server key within in the Firebase-Project.
HTTP-Post-Content: Sample
{
"notification": {
"title": "Notification Title",
"text": "The Text of the notification."
},
"project_id": "<your firebase-project-id",
"to":"the specific client-device-id"
}
Google Cloud Functions make it now possible send push notifications from device-to-device without an app server.
From the Google Cloud Functions documentation:
Developers can use Cloud Functions to keep users engaged and up to
date with relevant information about an app. Consider, for example, an
app that allows users to follow one another's activities in the app.
In such an app, a function triggered by Realtime Database writes to
store new followers could create Firebase Cloud Messaging (FCM)
notifications to let the appropriate users know that they have gained
new followers.
Example:
The function triggers on writes to the Realtime Database path where followers are stored.
The function composes a message to send via FCM.
FCM sends the notification message to the user's device.
Here is a demo project for sending device-to-device push notifications with Firebase and Google Cloud Functions.
Diego's answer is very accurate but there's also cloud functions from firebase it's very convenient to send notifications in every change in the db. For example let's say you're building chat application and sending notification in every new follower change.
This function sample is very good example.
For more information about cloud functions you can check official docs.
I have an app that has a "send feedback to developer" section. I also have a User collection in my firestore database. When a user logs into the app, I have that Users data update their FCM token with the following code in my SceneDelegate.swift:
import Firebase
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
authListener = Auth.auth().addStateDidChangeListener({ (auth, user) in
Auth.auth().removeStateDidChangeListener(self.authListener!)
if user != nil {
DispatchQueue.main.async {
let docRef = Firestore.firestore().collection("User").document((user?.email)!)
docRef.getDocument { (snapshot, error) in
guard let snapshot = snapshot else {return}
Messaging.messaging().token { token, error in
if let error = error {
print("Error fetching FCM registration token: \(error)")
} else if let token = token {
docRef.updateData(["FCMtoken":token])
print("FCM registration token: \(token)")
}
}
}
}
}
})
guard let _ = (scene as? UIWindowScene) else { return }
}
then in my feedback view controller i have this code to send my specific device (but you can look up/fetch which specific device you want in your database where the FCMtoken is stored where i have INSERT-DEVICE-TOKEN-HERE). The url to send to is "https://fcm.googleapis.com/fcm/send" and you can find YOUR-APP-FCM-KEY by going to your project settings in firebase, going to cloud messaging tab and its the server key.
func sendMePushNotification() {
let token = "INSERT-DEVICE-TOKEN-HERE"
if let url = URL(string: "https://fcm.googleapis.com/fcm/send") {
var request = URLRequest(url: url)
request.allHTTPHeaderFields = ["Content-Type":"application/json", "Authorization":"key=YOUR-APP-FCM-KEY"]
request.httpMethod = "POST"
request.httpBody = "{\"to\":\"\(token)\",\"notification\":{\"title\":\"Feedback Sent!\",\"body\":\"\(self.feedbackBox.text!)\",\"sound\":\"default\",\"badge\":\"1\"},\"data\": {\"customDataKey\": \"customDataValue\"}}".data(using: .utf8)
URLSession.shared.dataTask(with: request) { (data, urlresponse, error) in
if error != nil {
print("error")
} else {
print("Successfully sent!.....")
}
}.resume()
}
}
Use onesignal,you can send device to notifications or device to segments ,it can work with firebase in this way
Use onesignal functions to create a specific id,save it in a firebase database ,then when the id can be put in another function that is used to send a notification
Notes: 1-i am using it in my apps with firebase works perfectly
2-i can submit that code,just someone comments so i can find this answer
I'm very new to Android and since I'm a self learner I've been stuck with the following problem.
I have a simple code in MainActivity as
login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String sapCode = String.valueOf(sapcode.getText());
String userName = String.valueOf(username.getText());
String pwd = String.valueOf(password.getText());
if (sapCode.equals("017343") && userName.equals("root") &&
pwd.equals("root123")) {
message.setText("Login Successful!");
System.out.println("After successful and before Intent");
Intent intent = new Intent(context, HomeActivity.class);
startActivity(intent);
} else {
message.setText("Login Unsuccessful!");
}
}
});
As you can see in the above code by taking user credentials from view, I'm authenticating by giving hard coded values.
But Instead to that code, Indeed I should make rest call to my webapplication for login by providing these credentials in a post method. The URL looks like
http://myapp.co.in/login.do (or) http://myapp.co.in/rest/login
So that my java code inside my webapplication can access these values and authenticate based on those values.
Now My Questions are
1) How to make such request from my android app?
2) If authentication succeeded in my Web Application then how can I manage the session in my android app?
There are the problems I've been come across and I've been stuck with it. Any help will be appreciated. Thank you.
1. To make a client web-service call, use HttpURLConnection. The official tutorial is here;
2. To persist a session in Android, you can either make use of CookieStore or manually save, clear and retrieve the user_id or session_id in a SharedPreference.
There you go.
EDIT:
HttpClient should be used on Froyo & Eclair, while HttpURLConnection is preferred for Gingerbread and up. For the differences between the various connection approaches, see Android's HTTP Clients.