Storing Firebase Auth UID in Cookie while using Firestore - Is this secure? - firebase

I was recently having an argument with another programmer mate of mine regarding storing Firebase Auth UID (just the uid nothing else) in a cookie with sameSite: 'strict' enabled.
What's the argument about
Currently, I am working in a Nuxt JS project where I am saving the user's uid on onAuthStateChange() event in a cookie with sameSite: 'strict' enabled so that I can grab it in my serverMiddleware code and do stuff with it.
I have checked this firebase doc about managing cookie and it shows how to store the JWT idToken in a cookie and then in the server decode it.
In fact, that is who I initially coded my work. But due to some requirements, it was super helpful if I store the uid instead. So, I did that. Then I started reading about how can I hack my own data to see if anyone can harm my data from the uid in the cookie.
Then I stumbled upon to this firebase doc: Use the Cloud Firestore REST API which shows how to get the firestore data using REST API and I figured out that you need to provide Google OAuth 2.0 token in the header of the API call in order for it to work, otherwise even if you put the correct URL with all the collection name and everything (which is hard for an outsider to know, but lets assume he knows), you will get nothing but this:
{
"error": {
"code": 403,
"message": "Missing or insufficient permissions.",
"status": "PERMISSION_DENIED"
}
}
I have also tried to run code in browser console in order to hack the data out of my project. But That didn't work as well.
Now in order to get the Google OAuth 2.0 token, the person must need login access to my account which is not that easy as I have a unique long password along with 2 Step Authentication with phone OTP & push notification. Besides if anyone has login access to my Google account, he can easily go to console.firebase.com and see the data, so at that point, nothing will matter.
But I did say that if anyone is using firebase Realtime database then I will not recommend storing the uid in a cookie as the realtime database provides easy REST API without any authentication layer to fetch data. At that time I would recommend using JWT idToken instead.
So, what's the final question?
The final question is this:
If someone is using firebase auth & firebase cloud firestore (not realtime database) using firebase SDK in his project, is it secure to store just the uid in cookie instead of storing JWT idToken if it will reduce the code complexity and code execution time over using idToken?
I would love to know your thoughts on these as there are many super experienced devs beside two programmers arguing.
My friend keeps telling me that storing uid in the cookie is not sure, but when I asked him why exactly, he had no concrete answer. As what is secure and what is not a universal thing and changes as you change your tools. But in this exact context what do you guys think? I know that normally in most cases it is not a secure thing, but I am asking about this specific context only.

It is in fact fairly common to expose the UID of a user to other user to identify that user. See Firebase - Is auth.uid a shared secret?
There is nothing insecure about storing the UID in a cookie, nor in reading that cookie in your middleware. But if your middleware then assumes that the UID is the authenticated user, you have a security risk.
What is keeping any other user from putting your or my UID into that cookie, and thus getting access to your or my data?
Also note that UIDs don't change over time, so if ever one (even inadvertently) leaks, you could impersonate that user forever.
ID tokens on the other hand have a limited lifespan (currently about an hour), which limits the risk if they accidentally get exposed.

Related

Does createCustomToken(aUID) logout users currently authenticated with that same aUID

TLDR; Can multiple different users be authenticated and retain authentication via a generated custom token IF that custom token for each of those users is being generated always by the same UID? That is, User1 gets custom token generated by UID1 (via createCustomToken(UID1)) and then signed-in with signInWithCustomToken(), THEN User2 gets and signs-in with custom token generated using UID1, then User3 same thing etc etc, can ALL these users happily remained logged-in and experience no interruptions despite these other users being authenticated in this identical manner?
Long Version:
Ok, so I am trying to create a link-sharing system wherein a user who navs to this link can access a specific subset of my project's Firebase resources.
I have already tried using Firebase's signInAnonymously() to do this, but I dont like the way that Firebase does this for a whole host of reasons I dont want to get into.
The way i want to accomplish this is by:
generating a unique link (really a Firestore unique doc ID with some access data stored in that doc)
having the unauthenticated user navigate to some landing page, calling the cloud function and passing that unique link (lets call it a UID now)
cloud function, upon recieving this UID, will createCustomToken(UID), returning the token back to calling user
and the user will authenticate themselves with signInWithCustomToken(returnedToken) and access provisioned resources
Now, that is all well and good, but my question is:
If two (or any amount more people) people navigate to that same link and therefore pass and create token with the same UID, will they all be ok to continue happily using Firebase resources? Or is it because they got tokens created for them which utilised the same UID a sort of token-conflict is made, and therefore any next user who authenticates in this manner will revoke the previous user's auth token.
I havent been able to try this, and it seems like every question asked about these custom tokens relates to the generation and expiry time of them, which I understand. I wish the Auth docs were more clear on the mechnics and pitfalls of using Custom Tokens. I also havent been able to try it myself as it would be quite alot of refactoring, and was hoping someone could give me a straight answer to this.
Yes, a user can login on multiple devices without affecting other sessions at the same time irrespective of which auth method you use.
I'm not sure what the unique links are but it's not a good idea to pass the UID itself around if you function just takes a UID and returns a custom token as UIDs are pretty short and just a random string. It might be best to add a custom signed JWT in the links that contain the UID in payload so you can verify them before creating Firebase Custom Tokens.

AWS Cognito expired access token

In my application I have used aws cognito with next auth for user auth.
In the jwt callback that I have from api next-auth I receive an access token, which is then saved and sent to the client side. There, I save it in local storage and, among other things, I send it to my api which checks if it is correct.
The problem is that after an hour the access token expires and does not get a new one (always next-auth gives me old value). Has anyone had a similar flow and knows how to manage a session refresh? I will add that I am not automatically logged out because next-auth is managing it underneath, but it does not return the value of the new access token to me.
Do you have any ways how to manage this?
I can suggest a workaround that would take the least effort to solve this quickly. Amazon Cognito contains 3 kinds of tokens, the ID Token, Access Token and Refresh Token.
From the Amazon Cognito console, you can increase the validity of the token you're dealing with from there. A good idea is to refer to this answer.
Albeit you might need a couple of methods to assert security and robustness.

How to logout the user using Firebase Admin SDK?

So, I have created a cloud function using Firebase Admin SDK. The purpose of that function is to disable the user and after successfully disabling it, I want that user to be logged out from my application. I have disabled user but can't figure out how to log out the user.
I was wondering if there is any function of a workaround to achieve this?
A user that is signed in to your app has a ID token that is valid for up to an hour. Once that token has been created, there is no way to revoke it.
The typical way to handle your use-case is to also flag the user in a server-side database once you disable their account, and then check that flag in any operations.
For example, if your using the Firebase Realtime Database, and disable the user with Node.js, the code to also flag the user in the database could look like this:
// Disable the user in Firebase Authentication to prevent them from signing in or refreshing their token
admin.auth().updateUser(uid, {
disabled: true
}).then(function() {
// Flag the user as disabled in the database, so that we can prevent their reads/writes
firebase.database().ref("blacklist").child(uid).set(true);
});
And you can then check this in the server-side security rules with something like this:
{
"rules": {
".read": "auth.uid !== null && !root.child('blacklist').child(auth.uid).exists()"
}
}
This rule allows all users that are signed in (auth.uid !== null) full read access to the database, but blocks users who you've flagged (!root.child('blacklist').child(auth.uid).exists()).
For an (even) more elaborate example of this approach, see the documentation on session management.
There are two main types of tokens used in Firebase Auth that are relevant to your question here:
Refresh token
ID token (aka, access token)
Firebase ID tokens are short lived and last for an hour; the refresh token can be used to retrieve new ID tokens. Refresh tokens expire only when one of the following occurs:
The user is deleted
The user is disabled
A major account change is detected for the user. This includes events like password or email address updates.
https://firebase.google.com/docs/auth/admin/manage-sessions
So in your case, when you disable the user, the refresh token will be automatically revoked. This means that once the short-lived ID token expires, they won't be able to retrieve a new one.
But you want them to be logged out immediately after being disabled. There are two main considerations here:
if you control the well-behaved client application, you can voluntarily log them out in the client
if you want to truly protect against malicious actors, you can revoke the ID token on the backend
Voluntarily logging out in a well-behaved client
If the token is revoked via the Admin SDK, the client is informed of the revocation and the user is expected to reauthenticate or is signed out:
https://firebase.google.com/docs/auth/admin/manage-sessions#respond_to_token_revocation_on_the_client
However, the docs are very misleading here. There is no built-in behaviour to automatically inform the client of a revocation. Instead, you can follow the suggestions in this thread (https://groups.google.com/g/firebase-talk/c/cJjo9oknG6g/m/XG24x8SqEgAJ) which talk about how to implement this behaviour. The two main options presented are:
Use Firebase Realtime Database to build your own real-time "push" mechanism to detect revocations
Use currentUser.getIdToken(true) to force-fetch a new id token, which will detect the refresh token revocation, and log the user out (you should get an even on the onAuthStateChanged listener).
For option 2, note the parameter true passed in to forceRefresh. This is generally not a good option - you don't want to force refresh on every API request, but if you don't, it's hard to know when to do a force refresh.
When you refresh the page, the Firebase client SDK will typically automatically perform a force refresh.
Server-side detection
When a user's ID token is to be verified, the additional checkRevoked boolean flag has to be passed to verifyIdToken. If the user's token is revoked, the user should be signed out on the client or asked to reauthenticate using reauthentication APIs provided by the Firebase Authentication client SDKs.
https://firebase.google.com/docs/auth/admin/manage-sessions#detect_id_token_revocation_in_the_sdk
Note that using the checkRevoked=true option results in a network request from your backend to Firebase's backend, which is expensive. Again, it's hard to know when it's worth using checkRevoked. Perhaps it's worth the cost to always perform the network check on a small subset of highly sensitive APIs.
Summary
You should read through the docs in full (https://firebase.google.com/docs/auth/admin/manage-sessions) and see which approach suits you best.
Frank van Puffelen has already covered the other standard option - using rules to guard Firebase backend services.
But in general, there isn't anything that helps out of the box. If you understand the concept behind refresh tokens and id tokens, you'll notice that it's fundamentally not possible to revoke the ID token while retaining the performance benefits (ie, reducing network traffic) that is the entire reason for using the refresh+id model to begin with.
I'd just let the token expire, and accept that any "disable" can be delayed by up to 1 hour.

Should I try not to save Firebase Auth on LocalStorage

While preparing my web app for production I am noticing that Firebase saves a lot of users's data once they sign up/register to my app and these data is save on localStorage.
What is my concern is auto generated uid, I don't want users to be able to know their own uid and I don't want that piece of data to be saved on localStorage.
So I have two questions, should I concern about this ? since I do not have so much experience with authentication in general and I am afraid someone could do something...
Is there any way to remove the localStorage and firebase auth to work correctly ?
Cheers
Do not rely on uid to identify an authenticated user. You should only use the ID token JWT for current user, by calling currentUser.getIdToken() and if you are using your own backend server, verify the ID token using the Firebase Admin SDKs by calling verifyIdToken. Learn more about ID tokens: https://firebase.google.com/docs/auth/admin/verify-id-tokens
No , Because firebase auth is part of authentication with server database. if your trying to do like this then your application will not be able to signup or login.

Can I access the registration tokens of all users registered in my Firebase notifications?

Sometimes I want to send a message through Firebase notifications to one unique user, then I want access the token from that user, so I like to know what is the best practice for get that token at any time?
On initial startup of my app, the FCM SDK generates a registration token for the client app instance.
I can get that token, but if I save that token in Firebase realtime database, I think other people can access that data because it is "set persistent mode on" to access offline data.
My questions is:
Is it possible to get tokens of all users without save that in a database?
Can I get these tokens direct from Firebase Authentication? If not, what is the best practice for access these tokens?
I think other people can access that data because it is "set persistent mode on" to access offline data.
Simply save the registration token details to a secure node. Making sure that only you (or even including the user itself) to be the only ones that can access it. Read more on Understand Firebase Realtime Database Rules.
I can get that token, but if I save that token in Firebase realtime database, I think other people can access that data because it is "set persistent mode on" to access offline data.
Users won't be able to get the data they're not allowed to/wasn't designed to have on their device if you choose to restrict them.
Is it possible to get tokens of all users without save that in a database?
There is no API to get all the registration tokens related to your app. As mentioned in the documentation (emphasis mine):
After you've obtained the token, you can send it to your app server and store it using your preferred method. See the Instance ID API reference for full detail on the API.
It's the developer's (you) responsibility to send and store the registration token to a secure location.
Can I get these tokens direct from Firebase Authentication?
I'm not entirely sure what you mean by this. FCM Registration tokens are different from auth tokens. So, no.
If not, what is the best practice for access these tokens?
So long as you store the tokens in a secure location and make sure that you're always using the most recent/valid token, it should be good.

Resources