Best practice for Firebase authorization persistence and API calls - firebase

I've been following a tutorial to build a full stack website using firebase, react and redux. Log in sends a call to a back end function which uses
firebase.auth().signInWithEmailAndPassword for logging in. The IdToken is passed back to the client and stored in localstorage. Authentication and state persistence then relies on the client checking if the current date is past the expiry of the JWT token. API calls to the back end cloud functions also require an Authorization header using 'Bearer {IdToken}'.
This structure is causing me lots of headaches. I've done lots of reading and my current understanding is that firebase has it's own authorization persistence (?) that I can implement directly on my front end. Then using a listener I can automatically get new Id tokens on auth state change. This would solve my problem of the tokens expiring every hour. From what I've read local storage of the tokens is also a security risk.
I'm unsure as to how that affects authorization of my function calls. Should I still use the authorization header or is there a more elegant firebase way of doing that?

If you use Firebase Authentication's built-in providers, they indeed automatically persist the sign-in information information on most clients, restore it upon restart, and refresh the ID token just before it expires.
So if you use one of the standard providers, you can just get the user's ID token and then pass that to your Cloud Function.
You can even skip that step by using Callable Cloud Functions. For those, the Firebase Functions SDK passes the ID token along automatically, and the server automatically decodes and verifies it, and passes it to your code as context.auth.

Related

Firebase custom auth in server-to-server scenario

I need to implement a scenario where, after a file is uploaded to Google Cloud Storage, a function is triggered and processes the file. In this case, processing basically means sanitizing the file, storing it into Firestore and making it accessible via another HTTP-triggered function (a REST API of sorts).
Both user-facing ends of this process (a file upload and HTTP function) need to be secured. The process will be used in server-to-server scenario: one side is going to be a backend written in either Node.js or .NET, the other will be my Firebase solution (Cloud Storage and HTTP-triggered function as per above). In Firebase, I am going to maintain a custom set of users that should have access to the system - my idea was to use a simple system where each user will have a client id and a client secret (basically an oAuth client credentials grant type).
Based on what I read online, an only option to implement this is to use [Firebase auth with custom tokens][1]. I found lots of examples online on how to do that, but it was always about client-to-server scenarios (e.g. a Javascript web app talking to REST API). Server-to-server scenarios were not mentioned anywhere and indeed, I am unsure how to go about implementing it - I can call auth.createCustomToken(uid) just fine in my HTTP Firestore function, but there seem to be no server-side libraries I could use to call auth.SignInWithCustomTokenAsync(customToken).
To sum it up:
How can I use Firebase auth with custom tokens in server-to-server
scenario, where I need to sign in using a previously generated
custom token from a server environment?
If it is not possible,
what's the other alternative to securely implement the
above-described architecture?
I've contacted Google Support and if anyone else is struggling with this, in server-side scenarios, recommended approach is to call signInWithCustomToken endpoint in Firebase Auth REST API.

How to "sign out" of firebase with firebase rest api

I'm using firebase rest API and I'm trying to imitate firebase.auth().signOut(). I imagine I would go ahead and invalidate the firebase ID token. Is that the proper way to do so or should I just let the token expire on its own?
Just delete the client token from memory and storage so that it doesn't get used again. That's basically what the client SDKs will do. The backend doesn't retain any sense a user being signed in - either the token is valid for some API call, or it is not.
You can see for yourself what the client SDKs do, since they are all open sourced. The JS SDK can be found here.

Should I cache Firebase idTokens for a while, after I authenticated it in node admin sdk?

I am building an app, where I need to use my own backend besides Firebase. I need to authenticate a logged-in user in my backend too. So I found this tutorial which does this. I send an idToken and verify this header in admin sdk in my node, based on the docs. I thought I could cache this token with redis or just a js map after the first verification for 10 minutes or as much as a user session would take, to speed things up, instead of verifying each request in a 10 min sess. I could probably cache the token in the phone too for some time?
My question is, what security consequences would this bring? Thank you.
To clarify I am not using custom tokens, I will be using the built in Firebase Authentication.
The convention is to send the ID token to your backend with every request. It's not expensive to verify the token with the Admin SDK as shown in that documentation. It doesn't cost any money.
Typically what you're supposed to do is use a listener to detect when the ID token changes (it will be refreshed automatically every hour), and keep using that token until the SDK delivers a new one to your callback. In web clients, you're supposed to use onIdTokenChanged to register a callback to get changes to this token over time. There is no need to persist or cache this token - simply use whatever the callback most recently provided.
Some of the Firebase backend services keep a small cache of recent ID tokens, and their decoded results. So if they receive the exact same token, they'll use the already decoded result. This is a riskless operation, as the decoding operation is idempotent: the same input will always deliver the same output.

How can I send the parameter with the firestore get method?

My project is creating a website using firebase, but it is using the internal authen micro service instead of Firebase authen.
Every time the user logs in, the internal authen service will generate a token (I call it client_id), and send it to the client.
This token is also stored in the user collection.
Please help me how to write rule for the user via this client_id.
If it is write role, I can send the client_id via mothod update, delete, create and get it out by
request.resource.data.cliend_id and check it.
But if it is read role, I don't have any way to send to the client_id via the get method to authenticate users
I even thought of replacing all the get methods with the update methods to pass the client_id
But the response of the update method is just the update_time, not the object I updated
Firebase RTDB & Firestore Rules uses their own auth only. In every request that firebase client library sends uid along with jwt token and other security parameters. These are fundamental to firebase's working and thus can't be replaced.
As Aleksey mentioned, you can try custom auth. It is specifically tailored for such use cases only.
There is no way to provide extra data to security rules for the purpose of limiting read operations. That would not be secure at all, because a client could simply fake whatever they want in the query.
You can only use information provided by Firebase Auth available in request.auth, the data in the document itself in resource.data, or the contents of other documents using get(). If you want to attach additional data to the user account, consider using custom claims.

Firebase Security Rules Without Firebase Authentication

I use Firebase to store real time status updates for an app. I have my own authentication system for logging users in. I would like to share the data I store on Firebase to vendors who use our API, but I want to make sure they have only read access to our data.
From what I've read, it seems like securing data by user must be done through Firebase's own authentication system. Is there a way to do this without using their authentication system (maybe through a token system)?
You can definitely generate Firebase tokens in your application code, with custom properties that may be subsequently used in the Firebase security rules. Take a look at Generating a Secure Token in the Firebase docs.
Also see Can a Firebase Security Rule check if someone has specific access rights?, where #Frank van Puffelen offered a more comprehensive role-based approach.
I ended up using a system where a vendor calls one of my APIs (protected by my own internal authorization system) that returns a token that the user can use to authenticate with Firebase.
I use PHP and there is a token generator written by the Firebase team here. Don't forget the JWT PHP library this token generator relies on.
The token generator takes what is called a Firebase secret (you can find this in your particular Firebase instance page) passed into its class constructor and returns a random token based on this secret.

Resources