Authentication with Firebase in React Native apps - firebase

I have a React Native App in which I use Firebase for database and authentication. I use custom authentication with Firebase where I generate a token on my server side code and pass on the token to the client and the client authenticates itself using signInWithCustomToken method. Earlier, we could specify an expiry period for the token and I could use the same token again and again. This was then changed in a later version to have an expiry period of one hour after being issued and it was mentioned that the Firebase SDK will make sure to maintain connections and the user wouldn't need to do the authentication again and again. I recently saw that in v3.6.2, there was some fixes to the authentication for react native
Fixed an issue that prevented user authentication states from
persisting when using Firebase Authentication with React Native
versions 0.37 and higher.
I am using the latest v3.6.6 at the moment. I still see that the user is authenticated every now and then when the app is foregrounded. I wanted to know how does authentication with firebase in react native apps work. The user will put the app in the background at which point it would be suspended by the phone OS or even killed in some conditions. When the user put the app in foreground again, should I expect that the Firebase SDK would make sure that the connection to firebase stays on or would it authenticate with firebase again?

Related

FirebaseAuthentication Plugin not updating local FireBase.Auth JS with signed in user

Background
I have an almost finished webapp already working with the following stack
Firebase
React/TypeScript
Context
I'm adding Capacitor to my WebApp so I have a native app where I can send push notifications, and have presence in App Store, Google Play Store. The application already works on its web version, so there is no rule (Real Time Database, FireStore, etc) problem, no credentials problems at all on its web version, all well tested.
Problem
I've added Authentication to my application via Firebase Authentication, which works well, and I have also connected the Native iOS version to it, as it's described in the documentation
Auth flows works fine, User/Password & Google sign up are working fine and actually triggering the methods like onIdTokenChange and OnAuthStateChange from the official Firebase Auth library, in both cases, iOS and WebApp, and also the OnAuthStateChange from the Capacitor plugin (in both clients too).
The problem is that the Firebase JS library remains somehow in a unauthenticated state, where any call to FireStore, Database, or Storage, ends up in "Permissions Denied" error (Only on iOS). Once the Token ID has changed, I can see that currentUser is NULL, and the "signed in user" is not propagating to the Firebase official library from the Capacitor Plugin.
Once I have connected the Capacitor Firebase Authentication plugin, I was expecting that the Firebase official JS library was going to be updated, I've also used Firebase Authentication with IndexedDB local persistence as follows (when being in Native) as follows:
export const Authentication = Capacitor.isNativePlatform() ? initializeAuth(FirebaseApp, {
persistence: indexedDBLocalPersistence
}) : getAuth(FirebaseApp);

Firebase authentication flow for backend

So I started a test project with Golangg which I expore different technologies and got into some google firebase for authentication provider for users. I implemented the flow with registering users which require user/password. After that I wanted to do login (only backend vie rest api) turns out you can't since go verify user by user/password you need the google sdk works with iOS Android Web C++ Unity. The only work around i could do is get user by ID which i saved in my db then issue custom token, which then needs to be verified by method
signInWithCustomToken
but this is not implemented in the Golang lib, you need to call rest api for this
https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=[API KEY]
but there is a function for that in js. So if I only want to do the whole service backend I seems I can't do authentication with google Firebase.
How this whole flow should look like implementing only backend service?

Firebase Phone Auth is not working in flutter app neither in iOS simulator nor in a real device

I have been trying and searching various methods to make Firebase Phone Auth to work in my flutter application. (There is an open issue talking about conflicts between Firebase Cloud Messaging & Firebase Phone Auth, but I am unsure if my issue is related to that. I do use Firebase Cloud Messaging which works perfectly fine.).
In iOS simulator, whenever I call FirebaseAuth.instance.verifyPhoneNumber, my app opens a web page for reCAPTCHA workflow, and returns back to the app. Then I see the error logs like below in verificationFailed callback. (It is expected to follow reCAPTCHA flow for iOS Simulator according to Firebase Phone Auth Doc)
flutter: Instance of 'AuthException'
flutter: {"error":{"code":403,"message":"Requests from this ios client application <empty> are blocked.","errors":[{"message":"Requests from this ios client application <empty> are blocked.","domain":"global","reason":"forbidden"}],"status":"PERMISSION_DENIED"}}
It is suspicious that error message is using <empty> as my application name, instead of my real app name (or default firebase app name which is __FIRAPP_DEFAULT), but I am unsure why that is happening.
In real iOS device, whenever I call FirebaseAuth.instance.verifyPhoneNumber, the app invokes verificationFailed callback again and I get the error with verifyPhoneNumberError as code and Token mismatch as error message. This is happening in both debug build as well as in release build.
I am using following SDK & library versions.
Flutter SDK = 1.12.13+hotfix.5
firebase_core = 0.4.3
firebase_auth = 0.15.4
firebase_messaging = 6.0.9
Has anyone been able to get Firebase Auth Phone auth working in iOS? I am stuck in this limbo state because I cannot seem to search any info online related to this. I have setup iOS APN, GoogleService-info.plist, Google Cloud Credentials multiple times so far with no luck. (Given that Firebase Cloud Messaging works perfectly fine, I doubt it is an issue with credentials or APN setup.)
Answering my own question since I figured out the root cause.
In Google Cloud Project that is connected to Firebase, I was able to find a set of API Keys that were created by Firebase.
https://console.cloud.google.com/apis/credentials
For each App you define and create in Firebase, a new API key will be auto-created in the API key section. In my case, there was one for 'iOS key (auto created by Firebase)' and another for 'Android key (auto created by Firebase)'.
Well, by default, they do not impose any restrictions and you see a yellow triangle next to the key. So I added restrictions to those keys so that they can only be useable in my app. This is done by setting Application restrictions with corresponding bundle id for iOS and another app id for Android within each API key detail page.
This restriction was actually the reason that Phone Auth has not been working in my apps. Once I reverted the change back to None, I no longer encountered Token mismatch or AuthException.
Ideally, I should restrict these API keys to my app only, but it seems like my Flutter app is unable to prove its identity/appId/bundleId to google services, and Google had been rejecting requests from my App. This must be why I was seeing Requests from this ios client application <empty> are blocked. error message.
For now, everything is working because there is no restriction, but I will need to figure out why my app and its id association is not working as expected sooner than later, so that I can add restriction back.

Invalidate Firebase Token on Logout (React Native Firebase)

What is the correct way to invalidate a firebase token on react-native-firebase when user logs out?
Firebase's deleteInstanceId isn't available in react-native-firebase.
In the Github issues, the following method was suggested: firebase.iid().delete()
However, after using this method once, I wasn't able to get the user to continue receiving notifications (using a newly generated firebase token) -- and the only way to start receiving firebase messages again, was to delete the app
This behavior happened on both iOS and Android.
The reason I want to invalidate the token upon logout -- is to make sure that this device will not receive notifications that are only intended for the user to see when logged-in

Can Firebase be used without clients logging in?

I am working on a project that might use Firebase only for messaging. The goal is for the following to happen:
App registers with Firebase on startup
App sends Firebase token to our server
Our server sends Firebase messages to all clients via the token from step 2
Note there is no step where the user will log into anything or enter any credentials. I am a little confused if this is possible in a production app, as most Firebase documentation talks extensively about different ways to authenticate, either via username/password, OAuth, etc.
The server will be sending different messages to different clients, but that logic will be handled by the server and not by different types of registration to Firebase. I know Firebase supports groups, but to make a long story short it probably won't be leveraged.
Can all this be done on Firebase? Is GCM a better match for these requirements? I feel like we would be throwing away 95% of Firebase and just trying to force it to simplify the messaging part.
Firebase Authentication does not at all affect the way that Firebase Cloud Messaging works. FCM only cares about the token for the app on the device as a means to target the app for messages. It doesn't care at all if the end user is authenticated by any means. If you want to associate a token to a user somehow, using Firebase Authentication or some other system, that's up to you.
FCM is an evolution of GCM. They are powered by essentially the same components. Using GCM doesn't give you any additional constraints or flexibility than FCM, except for the path to integration in your app.

Resources