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

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.

Related

Update specific firebase auth session custom claims

i m using firebase auth in my app.
auth methods : custom auth and google sign in. user can login using any of the two.
user can have multiple auth sessions running in multiple devices.
now when the user logs in using custom auth then i set some custom claims[session id] while sending the custom auth token.
QUESTION
in case user signs in using google signin how do i make sure that the custom claim is only applied to specific session [using admin sdk to update custom claims] ?
use case : every session has a unique id so that it can subscribe to it and once the session id deleted from any other device the user gets log out automatically.
thnx in advance 🙏🙏🙏
This is not a use case supported by Firebase Authentication. Custom claims are attached to a user account, and will appear whenever that user signs in. They are not related to a user session, and are not temporary. If you need some sort of per-session permissions, custom claims are not going to help you out here.
It does appear to be possible to have something similar to per-session custom claims using Custom Tokens, and the custom claims will be "temporary" (not persisted on the Firebase user object).
Authenticate the user on the frontend using the typical Firebase process (Google Sign-In, email/password, etc.)
Send the token to your backend and validate it
Mint a custom token with the desired custom claim using the Firebase Admin SDK
Send the custom token to the frontend
Re-authenticate the user using signInWithCustomToken()
I've found this to be particularly useful when temporarily elevating or modifying a user's permissions (e.g. an admin performing a restricted action on behalf of another user).

Lazy registration with Auth0 and Firebase

In Firebase, it is possible to log in a user as anonymous with a token, and when the user decides to register, just update the credentials. I have a hard time understanding whether the same is possible with Auth0.
We are now using Auth0 as identity provider, the flow is the following:
The user is using the app anonymously with limited access.
User registers in the app with Auth0.
Auth0 issues a token
Firebase receives the token and lets the user use the restricted parts. All the data generated by the anonymous user is lost
What I want to achieve:
When the user starts using the app, Auth0 immediately creates a user token
The token is valid to access certain parts of Firebase database
If/when the user decides to register, their token remains valid but receives additional credentials
Firebase lets the user use the restricted parts
It's Konrad from Auth0 Community Team. Yep as Baskaro said unfortunately it's not supported from our side of stack. It will be great if you can submit it as a feature request to our product team using our feedback form (you will be contacted by one of our product managers within 10 business days):
https://auth0.com/feedback

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

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.

Keeping emails synchronized between Firebase auth and database

I am using Firebase Web for a SaaS solution. My purpose is to have access to users' email at any time, either for sending notifications or triggering alerts from the backend.
For security reasons, Firebase auth does not allow to list users' email or to fetch emails based on user IDs. As a consequence, I keep a copy of the email into a specific collection in the Firebase database when a user account is created. The copy is made by a Cloud function that is triggered on user creation (following guidelines: https://firebase.google.com/docs/auth/extend-with-functions).
Thanks to the copy available in the Firebase database, I can access users' email. However, my issue is when a user changes his email.
Firebase auth provides the updateEmail function that returns a promise. I use this last to update the email in Firebase auth. Then, when the promise resolves I update the user email in the Firebase database. However, this has a major drawback: all the logic is performed on the client side and since both operations are not performed in a transaction if the client refreshes or closes his browser (or assume it crashes), then it is possible that Firebase auth is updated but not the Firebase database, thus leading to an inconsistent state.
I looked at the documentation, expecting the possibility to trigger a Cloud function when user auth information is updated. Unfortunately, I cannot find such a feature.
Another solution I thought about is to update the database from the Web client. Then, this last triggers a Cloud function that updates Firebase auth with the admin SDK. This last solution works but bypasses the check performed by updateEmail that ensures the new email is not used by another account. Also, the account hijacking protection performed by updateEmail is evicted, which is really bad from a security point of view.
Any idea to solve this problem properly is welcome.
Here are a couple of options:
When calling updateEmail, update the email in your database first before calling updateEmail. THowever, if an error occurs, you need to catch it and undo that change in your db.
When a user wants to updateEmail, send their id token and new email to your server or firebase function http endpoint. There you verify the ID token with the admin SDK, then use the client SDK require('firebase'), using the uid from the ID token, admin.auth().createCustomToken(uid), then using client SDK, firebase.auth().signInWithCustomToken(customToken). You can then call user.updateEmail(newEmail) on the backend and save the email.
Always save the uid only and just use Admin SDK admin.auth().getUser(uid) to look up the user and get their email. This guarantees you get the user's latest email as you will not be able to catch the email revocation if the user chooses to do so.
No need to save anything. Use the CLI SDK to download all your users and their emails. Check https://firebase.google.com/docs/cli/auth#authexport
This is also better as you will always be able to get the latest email per user even if they revoke the email change.

Resources