How to logout the user using Firebase Admin SDK? - firebase

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.

Related

Is there a way to log out a specific user using firebase auth go sdk?

background of this question
I'm using firebase auth for user authentication on my app.
I realized that firebase doesn't have a log of user information changes, so I can't answer user questions about it.
So, I'm planning to move the feature of changing user account info (like email, display name, and password) from using the client-side firebase auth library to using server-side firebase auth SDK for the purpose of taking logs of these changes to use for user support. Also, I'd like to make logout a user who changes account info.
I've looked for the appropriate API on the document firebase.google.com/go/v4/auth and found UpdateUser function. The struct UserToUpdate which is a parameter of UpdateUser can set a new email address, new password and new display name, but I can't find to set the parameter to make a user logout.
my question
Is there a way to log out a specific user by firebase auth go SDK?
Firebase Authentication's client-side sign-in is based on ID tokens, which are valid until their built-in expiration (by default: an hour after they are minted). Since no server keeps a list of all the ID tokens it has minted, there is no way to mark a token as invalid on such a list either.
The common approach to revoke access for a user is to:
Revoke the refresh token, so that they can no longer mint new ID tokens with it.
Add the ID token(s) of the user to a self-managed list of revoked ID tokens.
Detect the presence of an ID token in this list from your server-side code and security rules.
Optionally detect the refresh token revocation on the client
Instead of logging the user out, you can also force-refresh their ID token/profile on the client to get the latest information from the server.

Synchronize users created with Firebase Auth to my custom backend

I want to use Firebase Auth for my user login/registration process. Everything else should be handled by my own backend (spring boot app + postgres db).
Now I'm asking myself how I can synchronize a new created user to my user table in postgres. I thought about the following:
REST call through client - Everytime I get a success event from the firebase sdk I call an additional request to my backend which sends uid, username etc.
Problem: What if my backend call fails but the register process was successful ? That would lead to an inconsistent state since (at least thats what I understanded) I can't easily rollback. That would lead to situations where a user can login into my app without my backend knowing the user. This would crash/ invalidate all my following queries (e.g. search after user xyz would lead to no result even though he/she exists)
Check the existence of the user in the postgres database
Here I would query the uid from the database (which I got from the jwt) and create a new user if it doesn't exists in every incoming request.
Problem: The user query is a unnessecary overhead for every incoming request.
Trigger with cloud functions - When I understood it right firebase auth is firing events when a new user is created in cloud functions. This could be used to make the external api call.
Problem: I dont know what happens when my external rest call fails at this point. Can I rollback the registration ? Will I be ever catch this event again ? I also proably would have an eventual consistency situation, since I dont know when the cloud function triggers. Furthermore I would prefer not to include cloud functions to my stack
Is there any way how I could do this in a transactional manner ? Did anyone else tried is using sth simular ?
Thanks for every help!
The easiest way is actually to not synchronize auth data, but instead decode and verify the ID token of the user in your backend code.
This operation is (by design) stateless, although Firebase's own backend services often implement a cache of recently decoded tokens to speed up future calls with the same ID token.
Apparently, I finally came up with a different solution:
Register user per Firebase SDK (e.g. with email + pw method)
Make a post-call to my own registration api including the resulting uid from the previous step and some metadata
API creates a new user including a column with the UID + Fetches the firebase token of the user and adds an internal claim that references to the internal Postgres UUID via Admin SDK.
Frontend gets the created user and hard refreshes (very important, since the previously fetched token won't contain the newly added claim !) the firebase token and verifies that it contains the token. If it does -> everything is cool, if not some oopsie happened :) That will require a request retry.
Later when you start your app you can just check if the passed token contains the custom claim, if not open the sign up/sign in page.
Every endpoint except the one for registration should check if the claim is set. If not just forbid the request.
How to set custom claims:
https://firebase.google.com/docs/auth/admin/custom-claims#set_and_validate_custom_user_claims_via_the_admin_sdk
You can use the Firebase Admin SDK to create the user account from your back-end instead of from the client.
So first you create the user in your database, then grab the ID and use it to create a user with the same ID in Firebase.
If all goes well, send a confirmation to the client and sign it in using the same credentials they entered.
Why not creating an endpoint in your backend service and call this endpoint when a client side authentication succeeds?
This method should do 2 things:
decode token to get access to Firebase user object (Firebase Admin)
Compare Firebase user with your internal user table. if it doesn't exist you can create it using firebase user object, otherwise do nothing.
This solution allows you to do other nice things as well (Syncing user info between Firebase and your internal db, providing a way to let a frontend know if this user is new or not, ...) at a relative small cost (1 get call per sign in)

Firebase Auth - Disable a user and prevent him interacting with the backend

If a user of my app performs some unwanted action, his account may be disabled by a moderator. However, even if disabled, he will be able to use the app if he is already logged in. How can I prevent this?
The code I use to disable a user is within a Cloud Functions and use the following:
admin.auth().updateUser(uid, {
disabled: true
});
Disabling a user's account prevents them from signing in to the app in the future, and prevents their ID token from being refreshed. But their current ID token is still valid for up to an hour.
To detect the disabling of the user account, you can add their ID token to a blocklist and check against that list. You'd typically do that in your security rules, in your server-side code, and (for good measure) in the client. For more on this, see the Firebase documentation on detecting ID token revocation.

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

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.

How to disallow disposable email in firebase auth email provider signup?

We are using firebase auth and firebase auth UI to authenticate a user.
We want to disallow or block those user's, who is trying to use a temporary mailbox for signing up (eg: https://www.mailinator.com).
There are 2 proposed solutions:
Do a client-side validation for the email ID? (Difficult to manage a blacklist of email providers in the client. Also, people can still use API to hack it).
After the user signs up, on onCreate user event, we can trigger a firebase function to validate the email ID against the blacklist, then we can disable or revoke the account. But here,
if we are disabling the user, he/she will get access to our app for next 1 hour as the client already gained the ID token.
If we are revoking refresh token, we'll have to again wait for 1 hour or write the rule to make a query to Firestore to check if user access is revoked. (Better if we can avoid this query)
Is there a better or native way to solve this issue?
If we are not getting any other solutions, we'll choose to go with 2nd option (revoking refresh token).
I would do a combination of both solutions you proposed. Doing the client side check will trip up most people and for the more tech savvy that try to get around it, your onCreate trigger will deal with them.
You could also add their uid to a blocked list in the realtime database from your onCreate trigger.
Then you can listen to it on the client and log them out. And for database rules you can check if they are in the block list and so block the read/write rule.
a regularly updated service to check DPA is already being maintained.
Do a simple get request to:
https://open.kickbox.com/v1/disposable/{user_email}
this would return the response
{
"disposable": true
}
if email id is disposable.
you can send the get request with complete email id or just the domain.
e.g. https://open.kickbox.com/v1/disposable/jamond67#zdecaesgl.com
or https://open.kickbox.com/v1/disposable/zdecaesgl.com

Resources