UNAUTHENTICATED exception when using Firestore from GAE development server - android

I'm making an Android app that uses Cloud Endpoints Framework for the backend API. I'm testing the backend using the App Engine development server. In one of the backend functions I try to make a call to get a document from a Firestore database but I get this error:
com.google.api.server.spi.SystemService invokeServiceMethod
SEVERE: exception occurred while calling backend method
java.util.concurrent.ExecutionException: io.grpc.StatusRuntimeException: UNAUTHENTICATED
at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:500)
at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:479)
at com.google.api.core.AbstractApiFuture.get(AbstractApiFuture.java:57)
...
I believe that I have the service account setup properly. I have the environment variable GOOGL_APPLICATION_CREDENTIALS set to the path of the service account key. I'm also following the guide for instantiating and calling Firestore:
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
FirestoreOptions firestoreOptions =
FirestoreOptions.getDefaultInstance().toBuilder()
.setProjectId(projectId)
.build();
Firestore db = firestoreOptions.getService();
db.collection(collectionId).get().get();
Is there something I'm missing here to be able to call Firestore from GAE?

After fighting with this issue for some time, I incidentally found a temporary workaround. It seems that the db is indeed not authenticated yet and adding a call after getting the service to get the request meta data seems to trigger the authentification...
Firestore db = firestoreOptions.getService();
try {
// somehow without this it does not work on the local server
db.getOptions().getCredentials().getRequestMetadata();
} catch (IOException e) {
e.printStackTrace();
}
... // db access works on local server!

Related

Can I use SafetyNet with firebase functions?

I am trying to implement SafetyNet in my app. I also, don't have a server, and I am using Firebase Firestore and Firebase Functions.
My knowledge about Firebase Functions is very limited. And I was wondering if I could somehow use the functions to help me with the SafetyNet attestation. As I see, I should be producing a nonce on the cloud, send this nonce to the app, use it to attest, and send it back to the cloud to verify the integrity correct?
But I can't seem to find anywhere on how to do this. Can anyone point me in the right direction?
YES
Sorry for the excitement there, but this is possible since a few weeks ago through a new feature called Firebase App Check.
With App Check, you always end up with a two-step process:
Use an attestation provider (such as SafetyNet) in your application, so that information about the app is attached to each request it makes to Firebase.
Then at some point in time, when enough of your app requests have this information attached, check for the app information in Cloud Functions, or enable the check in one of the other supported services.
If you check the documentation on enabling App Check enforcement for Cloud Functions, you'll see that it mostly boils down to this check in the code:
exports.yourCallableFunction = functions.https.onCall((data, context) => {
// context.app will be undefined if the request doesn't include a valid
// App Check token.
if (context.app == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called from an App Check verified app.')
}
// Your function logic follows.
});

Amplify.observe not updating based on changes to DynamoDB

I am currently making a call to my server to make a change in the Datastore and listening for another change to it. I do not receive any new changes from the DB despite the database being changed correctly on the backend.
I recently upgraded amplify from 1.4.2 to 1.6.8 and this is when the issue started to show up.
Amplify.DataStore.observe(Profile::class.java,
{ observationCancelable ->
//ERROR
},
{ changedItem ->
when (changedItem.item().state) {
//DO Business logic
}
},
{ exception ->
//ERROR
},
{
}
)
When I query the datastore I am getting outdated results that are not the same as the data on DynamoDB. Is there any way to figure out why the local datastore is not being updated? Could it be an issue with the configuration with the server? Or is there some setup step that I have missed?
Edit: Added some extra details below
So a few more details I wanted to add to this that seem way more relevant as well as updates based on my research. I am switching between endpoints(dev to testing environments). It would seem that the dev environment is working fine with the application, using the datastore correctly and doing the proper AppSync. But in the new testing environment, when the app starts, it gets the latest version of the datastore but it fails to do any AppSync despite being able to make changes to the backend.
Here is an error I am getting when the app attempts to subscribe to the Profile object in the back end
amplify:aws-datastore: Unauthorized failure for ON_CREATE Profile
amplify:aws-datastore: Releasing latch due to an error: Subscription error for Profile: [GraphQLResponse.Error{message='Not Authorized to access onCreateProfile on type Subscription', locations='null', path='null', extensions='{errorType=Unauthorized}'}]
Is there some config file that I should be looking at to compare with to make sure that the endpoints match or some access key that the app needs?

Multiple public Firebase Database Instances in Android

I'm working on an assignment. I've to use Database provided by a provider 'hacker-news'. Also i've to use Firebase Authentication. I've setup a new project in my own account. Retrieving data from Hacker-news database works with below line. I'm able to fetch publicly accessible data with firebase child() APIs is
database = FirebaseDatabase.getInstance("https://hacker-news.firebaseio.com/");
But when i implemented Firebase Authentication and once user logs in it is giving error
Provided authentication credentials are invalid. This usually indicates your FirebaseApp instance was not initialized correctly. Make sure your google-services.json file has the correct firebase_url and api_key
I've spent lot of time on internet and found a link to implement multiple databases in single project -
Working with multiple Firebase projects in an Android app by Google
This works only if you are the owner of those Databases. Is there anyway i can access Hacker-news Database using SDK not REST-API?
FirebaseOptions options = new FirebaseOptions.Builder()
.setDatabaseUrl(getResources().getString(R.string.dbURL))
.setApiKey(getResources().getString(R.string.api))
.setApplicationId(getResources().getString(R.string.appID))
.setProjectId(getResources().getString(R.string.projectId))
.setStorageBucket(getResources().getString(R.string.storageBucket)).build();
//set all variable above as your need
boolean hasBeenInitialized=false;
List<FirebaseApp> fireBaseApps = FirebaseApp.getApps(getApplicationContext());
for(FirebaseApp app : fireBaseApps){
if(app.getName().equals("any_name")){
hasBeenInitialized=true;
}
}
if (!hasBeenInitialized) {
smaTeacher = FirebaseApp.initializeApp(this, options, "any_name");
}
database=FirebaseDatabase.getInstance(FirebaseApp.getInstance("any_name"));

Firestore fails to retrieve data after reconnecting to the Internet

I'm using Firestore with the Android SDK (11.6.2) and I'm hitting an exception when my device was offline and reconnects to the Internet.
When requesting a document, firestore fails with the following task exception :
com.google.firebase.firestore.FirebaseFirestoreException: Failed to get document because the client is offline.
However, the device is connected, I can make network requests beside using Firestore and they succeed.
This error is not consistent, sometimes the request will succeed right after reconnecting to the Internet. Sometimes, the request fails again and again, then succeeds, sometimes more than one minute after the device has been reconnected to the Internet.
Here is a sample request that produces the exception:
val docRef = firestore.collection("foo").document("bar")
docRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("FirestoreSourceSet", "Get document success")
} else {
Log.e("FirestoreSourceSet", "Get document error", task.exception)
}
}
I'm not using the offline capabilities of Firestore, thus the FirebaseFirestore instance is initialized the first time with the setPersistenceEnabled(false) flag:
val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(false)
.build()
val firestore = FirebaseFirestore.getInstance().apply {
this.firestoreSettings = firestoreSettings
}
Why is Firestore returning this error even though the device is online? Am I missing something in the Firestore configuration that would avoid this error?
I tried upgrading Firebase to the 11.8.0 version, but I encounter the same behavior.
Logs
These are the logs while trying to fetch sync some data with Firestore (which begins with a document fetch) after leaving airplane mode: https://pastebin.com/xDMG2Pzj
The network is already available before the first Firestore call, as I waited for the Wifi to settle, and check it using the ConnectivityManager of Android before proceeding with Firestore.
The multiple calls are because I manually retry using a button each time I get the error until the document is successfully retrieved.
The first line of the log is when I turn the airplane mode one, which closes the stream of Firestore.
Edit: Issue
Firebase doesn't have a public tracker, but I reported the issue using their report tool, and made a repo that reproduces the issue.
They acknowledged the issue but could not provide an ETA, so we have to wait:
If we release the fix, we will announce it in our release notes page.
This is still an issue as of firestore-core 17.0.4
From the official documentation:
To use offline persistence, you don't need to make any changes to the code that you use to access Cloud Firestore data. With offline persistence enabled, the Cloud Firestore client library automatically manages online and offline data access and synchronizes local data when the device is back online.
When you initialize Cloud Firestore, you can enable or disable offline persistence. So, when using the following line of code:
val firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(false)
.build()
You actually set the persistence to false, you are disabling this feature. To solve this, just remove this line of code. Firestore has .setPersistenceEnabled(true) by default.
This issue was fixed by the release 17.1.5 of Cloud Firestore.
See the official changelog https://firebase.google.com/support/release-notes/android
Cloud Firestore now recovers more quickly from bad network states.
Using my reproduction project with the version 18.0.0, the issue is indeed not present.
I'm facing the same issue since 2018 and have not yet found a proper solution. It is still happening with version 22.1.2 of the Firestore library for Android. As commented in the source code of DocumentReference, this exception is thrown when the client is offline and the requested document is not available in the local cache. There is also a recent explanation of this behaviour by Denver Coneybeare.
This exception might occur for DocumentReference.get() calls. Here's an exemplary stack trace:
com.google.firebase.firestore.FirebaseFirestoreException: Failed to get document because the client is offline.
at com.google.firebase.firestore.DocumentReference.lambda$getViaSnapshotListener$1(DocumentReference.java:331)
at com.google.firebase.firestore.DocumentReference$$Lambda$2.onEvent(DocumentReference.java:8)
at com.google.firebase.firestore.DocumentReference.lambda$addSnapshotListenerInternal$2(DocumentReference.java:504)
at com.google.firebase.firestore.DocumentReference$$Lambda$3.onEvent(DocumentReference.java:16)
at com.google.firebase.firestore.core.AsyncEventListener.lambda$onEvent$0(AsyncEventListener.java:42)
at com.google.firebase.firestore.core.AsyncEventListener$$Lambda$1.run(AsyncEventListener.java:2)
at com.google.firebase.firestore.util.Executors$$Lambda$1.execute(Executors.java)
at com.google.firebase.firestore.core.AsyncEventListener.onEvent(AsyncEventListener.java:39)
at com.google.firebase.firestore.core.QueryListener.raiseInitialEvent(QueryListener.java:176)
at com.google.firebase.firestore.core.QueryListener.onViewSnapshot(QueryListener.java:95)
at com.google.firebase.firestore.core.EventManager.addQueryListener(EventManager.java:97)
at com.google.firebase.firestore.core.FirestoreClient.lambda$listen$6(FirestoreClient.java:160)
at com.google.firebase.firestore.core.FirestoreClient$$Lambda$6.run(FirestoreClient.java:12)
at com.google.firebase.firestore.util.AsyncQueue.lambda$enqueue$2(AsyncQueue.java:436)
at com.google.firebase.firestore.util.AsyncQueue$$Lambda$2.call(AsyncQueue.java:1)
at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor.lambda$executeAndReportResult$1(AsyncQueue.java:322)
at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$$Lambda$2.run(AsyncQueue.java:1)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.google.firebase.firestore.util.AsyncQueue$SynchronizedShutdownAwareExecutor$DelayedStartFactory.run(AsyncQueue.java:229)
at java.lang.Thread.run(Thread.java:919)
I'm sorry if this answer does not solve the problem, but this information would have been too long for a comment on the original post.
I also have the same problem. There is workaround - application waits some time and makes another attempt to get the data from server.
Here is mockup (this is Flutter/dart):
List<Course> items;
Widget build(BuildContext context) {
...
loadData();
...
//building th UI with data from items list
...
}
loadData() async {
//is not loaded but there is internet connection
if (!isLoaded&&isConnected) {
try {
querySnapshot = await query.getDocuments(source: Source.server);
}
catch (ex) {
print(ex);
Future.delayed(Duration(seconds: 10), () {
// setState to trigger build 10 seconds later to make one more attempt
setState(() {
isLoaded = false;
});
});
return;
}
// here goes the code to handle the result
items = querySnapshot.documents.map((s) => Course.fromDb(s)).toList();
}
this may help
Java:
FirebaseFirestore db = FirebaseFirestore.getInstance();
//to reconnect
db.terminate();
db = FirebaseFirestore.getInstance();
Kotlin:
var db = Firebase.firestore
//to reconnect
db.terminate()
db = Firebase.firestore

Eventual problems getting response in mobile clients after doing insert from azure mobile service

I have an app that runs on android mobile smartphones and connects to azure mobile service backend (based on node js). Basically what I do is insert data to a table in the mobile service database. In the mobile app, after inserting my object I check if the response object has an id different to null, in that case I delete the row in the local sqlite database, if id equals "null" then I retry the operation later. The problem is that frequently I don't receive the id, so that id="null" and I retry operation, nevertheless when fetching the azure database the row was successfully inserted.
Here is part of my code:
if (downeventstable == null && !error)
downeventstable = FirstmenuScreen.mClient.getTable("downevents" + servicio, downevents.class);
boolean error2 = true;
try {
downeventstable.insert(dwnevent).get();
error2=false;
} catch (Exception e) {
error2 = true;
break;
}
if (!error2 && dwnevent.getId() != null) {
// if no error and id was received deletes row locally in sqlite
}
I guess that the problem is caused by a bad quality of the mobile network, maybe the app lost connection after a successfull insertion in azure and didn't get the response object. How may I know if the data was inserted in azure and treat these situations?
If your insert was successful and you try to re-insert the same record with the same ID later, you'll get a 409 conflict. You can handle this in your sync conflict handler if you're using offline sync, or just exception handling if you're using a regular table.
Here's a Xamarin sample that handles the 409 conflict, which is MobileServiceConflictException in C#. You would do something similar in Java. You can test this out by using a REST client and seeing that you get a 409.
Btw, it sounds like you are doing a lot of manual work with your own SQLite tables. You might want to consider using the offline sync feature that is built in, which will do the retries for you: Add Offline Data Sync to your Android Mobile Services app.
Note that Mobile Services is being deprecated, so we recommend that you upgrade your code to Mobile Apps if it is a new app. See Announcing Azure Mobile Services transition to Azure App Service.

Categories

Resources