Firebase and Google Maps API keys result in a wrong configuration
Description
I think the plugin extracts wrong API keys (google_api_key and google_crash_reporting_api_key) from the google-services.json file during the Android app build in a certain scenario. Possibly, the issue is partially caused by a wrong JSON file being generated by Firebase in the first place.
My Android app uses both Firebase Crashlytics and Google Maps. When I was adding the Google Maps integration, I followed the recommendations and I created dedicated API keys for Google Maps in Google APIs Console and I restricted them only to some of the app flavors by specifying the package name and SHA-1 restriction (also restricted to the "Maps SDK for Android" and "Places API"). In Firebase, both "staging" and "production" flavors are configured as separate apps in the same Firebase project, but they differ in package names and SHA-1 fingerprints.
Configuration
com.google.gms:google-services version: 4.3.3
com.google.firebase:firebase-analytics-ktx version: 17.5.0
com.google.firebase:firebase-crashlytics-ktx version: 17.2.1
com.google.firebase:firebase-crashlytics-gradle version: 2.2.1
Google APIs Console

Google APIs Console - Google Maps key 1

Google APIs Console - Google Maps key 2

Firebase - staging app

Firebase - production app

The JSON file I get from Firebase:
{
"project_info": {
"project_number": "922450535496",
"firebase_url": "https://[confidential].firebaseio.com",
"project_id": "[confidential]",
"storage_bucket": "[confidential].appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:922450535496:android:d7670fa2636a5081",
"android_client_info": {
"package_name": "[confidential].prod"
}
},
"oauth_client": [
{
"client_id": "922450535496-ls60[confidential]",
"client_type": 1,
"android_info": {
"package_name": "[confidential].prod",
"certificate_hash": "ba61e96fd3ddd4c56e359df0a3e8bc689cae4a69"
}
},
{
"client_id": "922450535496-mrti[confidential]",
"client_type": 1,
"android_info": {
"package_name": "[confidential].prod",
"certificate_hash": "5e014ddba1571358998ab939a934cae353640a2d"
}
},
{
"client_id": "922450535496-obbg[confidential]",
"client_type": 1,
"android_info": {
"package_name": "[confidential].prod",
"certificate_hash": "133e5c7fc7e7ff068b7227a20684c659bfd5a4ca"
}
},
{
"client_id": "922450535496-d585[confidential]",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCkOh[confidential]SSVSVSAz00"
},
{
"current_key": "AIzaSyAdVW[confidential]1dzU9qvu3k"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "922450535496-d585[confidential]",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:922450535496:android:02f104bc77b0e115",
"android_client_info": {
"package_name": "[confidential].stage"
}
},
"oauth_client": [
{
"client_id": "922450535496-ufah[confidential]",
"client_type": 1,
"android_info": {
"package_name": "[confidential].stage",
"certificate_hash": "b3645599ddfb1957a011c79dc5706d78e90f6ea0"
}
},
{
"client_id": "922450535496-ha7n[confidential]",
"client_type": 1,
"android_info": {
"package_name": "[confidential].stage",
"certificate_hash": "a26044bd4dbfe67e0f6fa052ca553a6b70d6e37e"
}
},
{
"client_id": "922450535496-vi8b[confidential]",
"client_type": 1,
"android_info": {
"package_name": "[confidential].stage",
"certificate_hash": "133e5c7fc7e7ff068b7227a20684c659bfd5a4ca"
}
},
{
"client_id": "922450535496-d585[confidential]",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCkOh[confidential]SSVSVSAz00"
},
{
"current_key": "AIzaSyAdVW[confidential]1dzU9qvu3k"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "922450535496-d585[confidential]",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
As you can see, the API keys in the api_key array are only the Google Maps keys and there is no Android key (auto created by Firebase) key.
Before I added Google Maps API keys in Google APIs Console, that part of the google-services.json file was different as it contained the Android key (auto created by Firebase) key.
"api_key": [
{
"current_key": "AIzaSyBtnw[confidential]le0_4ek0GM"
}
],
Generated resource
Now, when I build the app, it generates the resource file app/build/generated/res/google-services/stage/debug/values/values.xml with the following content:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="default_web_client_id" translatable="false">922450535496-d585[confidential]</string>
<string name="firebase_database_url" translatable="false">https://[confidential].firebaseio.com</string>
<string name="gcm_defaultSenderId" translatable="false">922450535496</string>
<string name="google_api_key" translatable="false">AIzaSyCkOh[confidential]SSVSVSAz00</string>
<string name="google_app_id" translatable="false">1:922450535496:android:02f104bc77b0e115</string>
<string name="google_crash_reporting_api_key" translatable="false">AIzaSyCkOh[confidential]SSVSVSAz00</string>
<string name="google_storage_bucket" translatable="false">[confidential].appspot.com</string>
<string name="project_id" translatable="false">[confidential]</string>
</resources>
As you can see, one of the API keys I created just for Google Maps APIs (AIzaSyCkOh[confidential]SSVSVSAz00) is used in both google_api_key and google_crash_reporting_api_key.
Moreover, that API key is restricted to a different package name and SHA-1 than I just built, which seems even worse 🤦
Authorization issue When I run the app, I see the following warnings and errors in the logcat:
09-11 11:14:00.743 5210-5247/[confidential].stage W/Firebase-Installations: Error when communicating with the Firebase Installations server API. HTTP response: [403 Forbidden: {
"error": {
"code": 403,
"message": "Requests from this Android client application [confidential].stage are blocked.",
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Google developer console API key",
"url": "https://console.developers.google.com/project/922450535496/apiui/credential"
}
]
}
]
}
}
]
09-11 11:14:00.743 5210-5247/[confidential].stage W/Firebase-Installations: Firebase options used while communicating with Firebase server APIs: AIzaSyCkOh[confidential]SSVSVSAz00, [confidential], 1:922450535496:android:02f104bc77b0e115
09-11 11:14:00.743 5210-5247/[confidential].stage E/Firebase-Installations: Firebase Installations can not communicate with Firebase server APIs due to invalid configuration. Please update your Firebase initialization process and set valid Firebase options (API key, Project ID, Application ID) when initializing Firebase.
Surprisingly, crash reporting seems to work nonetheless as I can see a crash I induced myself in the dashboard, but I have no clue why it works, especially considering the logs above.
i've downgraded from v 4.3.4 to 4.3.2 it was wrong matching build config and google-services.json
I can confirm this issue. Here is how to reproduce it.
- First activate the Maps APIs (Places, Geo, whatever) and configure your keys incl. restriction on Maps services, also add your SHA-1 for release and debug in there.
- Now go to Firebase and link the Google Cloud Platform project with a new Firebase project
- Add the app, add the SHA-1 and SHA-256 in the Firebase configuration
- Now download the google-services.json and open it
What you will find is the embedded key of Maps not the key that was generated by Firebase.
If you miss that and restrict your Firebase key properly to only be able to access Firebase APIs you will end up with an error when trying to get the token:
FirebaseException ([firebase_messaging/unknown] java.io.IOException: java.util.concurrent.ExecutionException: java.io.IOException: FIS_AUTH_ERROR)
This was a terrible time-waster for me, I am not happy
@azabost Is this the right place to report a bug in Firebase? Ima gonna email them as well.
@martin-braun
@azabost Is this the right place to report a bug in Firebase? Ima gonna email them as well.
I have no clue if this is the right place. I hoped it is, at least partially, because one part of the problem, in my opinion, is the Gradle plugin developed in this repository. The other part is perhaps the Firebase web UI/service/something. If you find a better place to report this problem and you report it there, please let me know. I will gladly help you to press this issue.
@azabost I had a long lasted back and forth communication with the Firebase Email support and a kind person took my problem to the devs. Few days ago he reported:
Upon checking again with the team, there has been a recent launch that can resolve the issue. Basically, developers may want to manually set which API Key is attached to their app. As long as the key they set remains valid, this key will persist during future config file downloads.
To update the API Key associated with an app, you can utilize the API Explorer. The steps are:
Retrieve your API Key's ID (described below). Within the Firebase documentation, go to the REST patch endpoint page for the relevant app: Android iOS Web. In the "Try this API" panel, in addition to the app's name, set updateMask to api_key_id, and input the API Key ID into the request body. Execute the command. If the key is invalid, you will receive an error telling why it's invalid, and a link pointing to the Cloud console to update your key's restrictions. The main reasons a key would be invalid are if the key has package or platform restrictions that don't match the app.
If successful, the response will come back with status 200 and will display the newly updated API Key ID in the app's metadata.
To retrieve an API Key's ID:
Select the desired API Key on the Cloud Console API Credentials Page The key's ID can be found in the URL (I've attached a screenshot for your reference)
I tried that without success (error 400), but won't care, since I already grabbed and corrected my google-services files for this project anyways. For me it is important that no future projects will be affected. Today I set-up a new project and repeated all steps and it seems the issue is gone for new projects at least. I didn't check my existing project.
I'm feeling confident to say that the issue seems to be gone (for new projects).
I also faced with similar issue recently. In my case it's Firebase Cloud Messaging and Google Maps.
The api_key: current_key on downloaded google-services.json wrongly pointed to Maps API key.
Had to edit the google-services.json with the correct Firebase Android API key, to get FCM working.
@dwidc Is your project new or did you create the Google project a few months ago? You might want to get in touch with Firebase support:
- File a bug report.
- Make sure to include a link to this thread and also mention that I had the problem as well (it's not fixed for my project, but it was fixed for new projects on my end), my case number was 10170889
- Include your project ID and all that is necessary to identify the project on their end.
@martin-braun It's a relatively new Firebase and Google Maps project, created about 2-3 months ago.
Thanks for info, I'll file report to Firebase later.
@dwidc Then the API key linking between Google and Firebase is broke on your project like it is on ours and I think they will have hard times to fix it (based on my gut feeling when I was reading their answers on my request). You might be able to fix it yourself by re-creating the Firebase project or following the quote I did above (which didn't work for me). The issue was fixed on Mar 11 for new projects, thus new links between Google and Firebase.
If you can, I recommend you to just not deal with this issue. Grab your json/plist and fix the API keys within it by hand and never look back. This is what I did in the peaceful mind that it will never happen for new Firebase projects, again.
I can confirm there's a problem with the generated google-services.json file. In our case, we use a separate api key for each of our environments (dev, tst, prd). The keys are restricted to a specific environment by adding Android restrictions on the package name (e.g. com.myapp.dev).
However, when downloading google-services.json, each of the 3 keys is added to each of the 3 apps, so each app contains an array of 3 keys. When firebase requests a token for FCM, the first key (=the dev key) is used for all environments, resulting in a 403 FIS_AUTH_ERROR because the dev key is being used in the tst app.
We solved this issue by manually editing google-services.json, but this is less than ideal.
We have the same problem, in our case we have up to 30 different apps added to a firebase project with 30 different api_keys. Everytime i download a google-service.json file i have 30 apps and to each!! of these 30 apps we have 30 api_keys added, instead of one api_key for one app. So i need to edit each of these files and remove all the unnecessary api_keys.
Is there really no other solution for this?
@davidfrasch This is not what this issue is about. The thing you experience is actually intended by Google. For some reason their google-service.json contains all API keys for all apps, but only on Android. Google doesn't want you to have 30 apps in a project, unless they are related, in which case you can share the google-services.json across apps without any penalty.
If you, however have different tenants, Google expects you to create a separate Google Cloud project per tenant, which will result in a unique google-services.json per app. This becomes especially notable when you realize that there is an app count limit per Google Cloud/Firebase project, so you can't really scale up using just one Cloud/Firebase project.
I can already feel your pain, because I share it with you. We have to re-configure everything for every new tenant, because we have to create a new Cloud/Firebase project over and over again.
Suddenly self-hosting seems like a good way out, if there wasn't the Firebase dependency for reliable Android notifications .... (somebody should tell the EU ...)
@martin-braun Thank you for the well explained answer, yeah its a real pain. But i guess we cannot change it :)
