Crash in Firebase auth v2 -> v3 migration code - firebase

I have some code I put in my react-native app a couple of years ago to support the forced migration of users from v2 -> v3 authentication. I am using the Web version of Firebase (6.6.0) in my app (NOT react-native-firebase).
I recently had a user try to log in with an old v2 token found in AsyncStorage (local storage). The app crashed with the following error:
TypeError · undefined is not a constructor (evaluating 'new t.default.Promise')
The crash occured on this line of the migration code supplied by Firebase. I'm guessing this migration code is no longer supported and I should just remove it from my app. But what should I do instead if a person tries to log in with a saved V2 auth token? Can she simply log out and log in again? Or does she have to change her password? Or does she have to create a new account, losing her old data?.
I don't have a way to replicate this situation since I have no way of logging in to v2 authentication. So I would appreciate a clarification from the Firebase team. Thanks.

TLDR; I've decided to remove the migration code from my app. When someone fires up the app and a legacy token is loaded from AsyncStorage, I simply delete the token and present the user with a login page.
I corresponded with Firebase auth support and include their answers below. First off, they suggested changing firebase.Promise in the code to Promise as firebase.Promise doesn't exist any more. This fixed the crash. Then, to test, I found an old simulator image that still had a legacy token in its AsyncStorage. Working with that, I found that the response to the XMLHttpRequest to the exchangeToken endpoint result in a null response (after approximately one minute). This tells me the endpoint is dead and there is no point in trying to query it, thus it makes sense to remove the migration code altogether from my app (even if the endpoint were working, a 2-year-old token surely would have expired.)
Then the question is what to do to enable users in this situation to upgrade gracefully. Firebase support suggested I should export the user (I have quite a few but I don't have a way to identify them definitively), then delete the user and import again. I couldn't believe all that hassle was necessary so I managed to find a couple of friends with old accounts. They had both forgotten their passwords, but after resetting, they were able to log in easily. So based on this limited testing, I think all that is necessary is to have them log in again. If that doesn't work they can contact our support and we'll go from there.
EMAILS FROM FIREBASE SUPPORT
I understand you, it must be a very frustrating situation, let’s try to find a solution together. I have checked your case and, as you have mentioned, the library is no longer actively maintained, so I’ll escalate your case to our engineering team in order to get any suggestions for your case, please wait a little until they can answer us.
The engineering team has answered and, unfortunately, they have said that old auth tokens have been unsupported for a long time, they suggested you forked the library and try to change firebase.Promise(), which does not exist anymore and then convert that to Promise(), but they can guess other errors will pop up and probably you will need to fix the code.
Thanks a lot for the clarification, I’m so sorry for my misunderstanding. If you want to delete the migration helper, as a workaround, you can export all the users (or only the users having the old token, if you have identified them), delete the users and import them again. This process will re-create the user and it will have the auth latest version because the user would be like a new user, with the same credentials and authentication methods. After that, the user on his side, needs to update the application, log out and log in again in order to update the token.
Please try to do the described workaround with a specific and identified user to limit the scope in case of fail and let me know how it goes.
Nice to hear from you again! Yes, the users will have the same UID and password, as you can see Auth export, the format contains those data and a lot of other more. Unfortunately, based on this, there is no way to know which of the accounts have an old auth token, so, in order to do a test and error approach, I suggest you try to do this with one user (identified old auth token user) to minimize unwanted results.

Related

How to save user data in db, without logging in?

I am working on a simple app that allows users to search for something using an API and save it to view later.
However, I don't want to integrate authentication in the app. I can, but would rather not as a UX decision. Do you know of a way to generate a device token, that is unique to every device and can be used to store which assets a device has saved in the db?
I am thinking of expo push tokens as a possible solution, but that would require users to accept push notifications - so what happens if a user says no?
Sounds like you could just use react-native-uid to generate a unique id for your device and then store it in AsyncStorage and fetch it from there going forward.
For more inspiration, or perhaps just a more canonical way to do this... read up on suggestions surroundings the recently deprecated constant for installationId here:
https://docs.expo.dev/versions/latest/sdk/constants
I haven't used this before but if you're looking for something bullet proof then this is probably your goal of getting the same concept.
Firebase Anonymous Authentication might be ideal to use in this case. This can be used to create a user in Firebase auth without any credentials and can be useful especially when you are using either of Firebase's databases since you can use security rules with user's UIDs.
However, once the user logs out of the account by any means including but not limited to using sign out option in your app, clearing app data or uninstalling the app, the same account with that UID cannot be recovered. I looked up for AsyncStorage and apparently that gets cleared to if the app is deleted.

Firebase authentication vulnerability. Unknown users in firebase

So I have an app where I have enabled google authentication in my firebase project. 25 people I know were authenticated. When I logged in the backend I saw atleast some 80 entries with some weird sounding email addresses which should not be there. I had to delete all the entries manually, known and unknown ones (didn't needed any after sucessful testing). Now that I want to go live, I am really concerned as to how unknown entires entered my firebase authentication records?
This has recently happened 'again' to another new app/project of mine. This time I disabled that unknown email address and took a screenshot (attached).
I really really need to know and understand how safe is data on firestore. If someone can manage to 'hack' the Authentication part and add thir email to Authenticated list of users they may also be able to penetrate the database somehow in future. Please help me in understanding what is happening?
While researching on this, I could only find this similar question but the answer was just not enough explanation for me.
Unknown user in my firebase user authentication (Flutter/firebase)
firebaser here
Since the configuration data for your project is embedded in the application that you send to your users, any user can take that configuration data and then start calling the API with it. This is not a security risk, as long as you secure access to the data within your project correctly for your requirements.
See Is it safe to expose Firebase apiKey to the public?
What it means to correctly secure access to your data is hard to answer, as it depends completely on your use-case.
For example: the content-owner only access security rules allow a user to enter data in the database, and then they can access the data they entered. With these rules there's no risk if anyone uses the API (and not your app) to do the same. The security rules will ensure they only can access data they're authorized for, no matter what the source is the API calls is.
It may be related to the pre-launch report.
https://support.google.com/googleplay/android-developer/answer/9842757?visit_id=637478112313064713-650300184&rd=1#signin
Step 1: Provide test account credentials if your app has a sign-in screen
If your app has a sign-in screen and you want the crawler to test the sign-in process or the content behind it, you need to provide account credentials. Note: You do not need to provide credentials if your app supports 'Sign in with Google', which enables the crawler to log in automatically.
So I guess it is safe.
The user willwhiteapple#gmail.com is the apple testing when your application is in the process of validation from apple before deploy to TestFlight .

Problem with reading user data of an app developped with Firestore

I have been introduced to Firebase a few days ago. Since then I have been trying to discover more features and usage of Firebase, in particular, the usage of the Firestore/Realtime Database.
However, as I am reading into more details, I start to think of some questions. I hope someone that is familiar with Firebase can help me answer them
As for User authentication, I understand that I can use Firebase Authentication where I won't see their real password. However, technically, everything that user stores in my Firestore would be visible to me since I am the owner of the Firebase.
For example, if I were to develop a note/chat app, in which the user can access their notes/chat on the iOS app and also Android. That means all their notes data would be saved in my database. If it happens to contain some private data, then I would be able to read it?
Even if I set security rules, that would be only facing client-side, whereas, for me, the owner of the entire firebase data, I could see the whole thing. Surely, as a customer, you won't want to use an app knowing that I can see everything you write
I am not sure if what I said is true or not. If true, is there a possible solution?
Both of your statements are correct. This happens in most of the apps-websites, the admin or some core developers have full access to the data. That's why privacy policy and GDPR exist. You must specify what data you collect and for what reason. If you intend to use your user data for any other reason you must inform them. Be aware that if you disclose any user information without his permission you can be held liable.

Firebase refresh-token expiration

While testing the security of one of our product, a web application, using the REST API of Firebase we got surprised when we realised that refresh-tokens never expire in the V3 of the Firebase implementation, allowing any refresh-token to create new tokens forever.
While local-storage seem a reasonably safe solution today, we are concerned by the possibility that it could fail tomorrow, even for a short amount of time, and that we cannot stop someone from using any of these refresh-tokens.
Two factor authentication will help mitigate the issue, but the first step would become compromised nonetheless.
Is there a way to blacklist tokens, or similar behaviour, with Firebase, without handling all tokens exchange, such as minting, ourselves? We could not find such feature when going through the doc.
Any advice appreciated.
Authentication sessions don't expire with Firebase login. But the ID token will have to be refreshed hourly, to keep access to the services. If you disable an account, refreshing the token will fail and the account won't be able to access services anymore. There is no way to invalidate individual tokens.
Firebase recently implemented revokeRefreshTokens() inside the admin sdk. Although this will not let you kill an invalid JWT, it does allow you to prevent a refresh of the token (from my testing so far at least) and it allows cleaner control flow inside firebase database.
See Admin Manage Sessions For rough examples

In my meteor app, how do I make authenticated google API calls on behalf of my user?

Background: This is my first standalone web development project, and my only experience in Meteor is building the Discover Meteor app over the last summer. I come from about a year of CS experience as a side interest in school, and I am most comfortable with C and C++. I have experience in python and java.
Project so far: I'm creating a calendar management system (for fun). Using accounts-google, I have created user accounts that are authenticated through google. I have requested the necessary permissions that I need for my app, including 'identity' and 'calendar read/write access'. I've spent the last week or so trying to get over this next hurdle, which is actually getting data from google.
Goal: I'd like to be able to make an API call to Calendar.list using a GET request. I've already called meteor add http to add the GET request functionality, my issue comes with the actual implementation.
Problem: I have registered my app on the developer console and set up Accounts using the client ID and secret, but I have not been able to find/generate my 'API key' for use in the request. Here is the google guide for creating the access token by using my (already) downloaded private key. I'm having a hard time wrapping my head around an implementation on the server side using JS because I don't have a lot of experience with what is mentioned in the HTTP/REST portion of the implementation examples. I would appreciate some help on how to implement a handshake and receive an access token for use in my app. If there is a call I can make or some package that will handle the token generation for me, that would be even better than implementation help. I believe an answer to this would also benefit this other question
The SO answer that I've been referring to so far: https://stackoverflow.com/a/14543159/4259653 Some of it is in spanish but it's pretty understandable code. He has an API key for his request, which I asked this question to help me with. The accounts-google documentation isn't really enough to explain this all to me.
Also an unrelated small question: What is the easiest way to deal with 'time' parameters in requests. I'm assuming JS has some sort of built-in functionality that I'm just not aware of yet.
Thanks for your research. I have also asked a very similar question, and right now I am looking into the package you recommend. I have considered this meteor-google-api package, but it looks abandoned.
Regarding your question about time manipulation, I recommend MomentJS. There are many packages out there; I am using meteor add mrt:moment
EDIT: MomentJS now has an official package for Meteor, so use meteor add momentjs:moment instead of the mrt command above
Below is a snippet of what moment can do. More documentation here.
var startTimeUTC = moment.utc(event.startTime, "YYYY-MM-DD HH:mm:ss").format();
//Changes above formatting to "2014-09-08T08:02:17-05:00" (ISO 8601)
//which is acceptable time format for Google API
So I started trying to implement all of this myself on the server side, but was wary of a lot of the hard-coding I was doing and assumptions I was making to fill gaps. My security prof. used to say "never implement encryption yourself", so I decided to take another gander for a helpful package. Revising search criteria to "JWT", I found jagi's meteor-google-oauth-jwt on Atmosphere. The readme is comprehensive and provides everything I need. Following the process used in The Google OAuth Guide, an authorization request can be made and a key generated for making an API call.
Link to Atmosphere: https://atmospherejs.com/jagi/google-oauth-jwt
Link to Repo: https://github.com/jagi/meteor-google-oauth-jwt/
I will update this answer with any additional roadblocks I hit in the Google API process and how I solved them:
Recently, I've been running into problems with the API request result. I get an empty calendarlist back from the API call. I suspect this is becuase I make an API call to my developer account rather than to the subject user. I will investigate the problem and either create a new question or update this solution with the fix I find.
Fix: Wasn't including the 'sub' qualifier to the JWT token. Fixed by modifying JWT package token generation code to include delegationEmail: user.services.google.email after scope. I don't know why he used such a long designation for the option instead of sub: as it is in the google API, but I appreciate his package nontheless.
I'm quickly becoming proficient in this, so if people have meteor-related google auth questions, let me know.
DO NOT USE SERVICE ACCOUNTS AS POSTED ABOVE!
The correct approach is to use standard web access + requesting offline access. The documentation on the api page specifically states this:
Typically, an application uses a service account when the application uses Google APIs to work with its own data rather than a user's data.
The only exception to this is when you are using google apps domain accounts and want to delegate access to your service account for the entire domain:
Authorizing a service account to access data on behalf of users in a domain is sometimes referred to as "delegating domain-wide authority"
This makes logical sense as a user must be allowed to "authorise" your application.
Back to the posters original question the flow is simple:
1) Meteor accounts google package already does most of the work for you to get tokens. You can include the scope for offline access required.
2) if you are building your own flow, you will go through the stock standard process and calls as explained on auth
This will require you to:
1) HTTP call to make the original request or you can piggyback off some of the internal meteor calls : Package.oauth.OAuth.showPopup() -- go look at the source there are more nifty functions around there.
2) Then you need to create an Iron router server side route to accept the oauth response which will contain a code parameter that you will use to exchange for tokens.
3) Next use this code to make a final call to exchange the "code" for the token + refresh_token
4) Store these where ever you want - my requirement was to store them not at the user level but multiple per user
5) Use a package like GoogleAPI this wraps up Google API calls and refreshes when required - it only works when tokens are stored in user accounts so you will need to rip it apart a bit if your tokens are stored somewhere else (like in my case)

Resources