Firebase Security Rules Without Firebase Authentication - firebase

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.

Related

Protect Firebase Http Cloud Functions Using JWT Tokens or any other mechanism without using firebase user authentication

Edited
I am building a spa app to make some administrative tasks on the app/firebase easier. I don't have a separate backend for this app so I use firebase cloud functions directly from the spa client. I am also not using Admin Sdk , just Http triggers. I am using functions.https.onCall on functions invoked by regular app users. Since i didn't want to mix up regular users with the admin login , I implemented a separate login for the spa app. Since the admin is already logged in , I am looking for some kind of JWT key / API key based authentication to secure firebase functions implemented for these tasks.
One possible solution , as Frank van Puffelen mentioned in his answer , is to add firebase auth , store the UIDs of the admin users and check if the request came from them using getIdToken() in the cloud function. Is this the best practice or is there an alternate to approach this.
Any input is appreciated.
The common approaches here are to:
Either keep a list of the UIDs of the admin users in a place that your Cloud Function can access, for example in the code itself or (more likely) in a cloud-hosted database.
Or add a custom claim to the ID token of admin users.
In either case, your Cloud Functions code can then ensure the user is authorized to call the end point.

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.

Secure app using firebase auth to stop malicious use of the key which is on the client

I was wondering how to to secure firebase auth. I plan on using firebase JUST for user authentication (not using firestore or realtime db). Since the API key is exposed on the client, my fear is that a malicious user can find the key and start using it inappropriately. So far I've done the following to try to improve security:
Limit key use to a specific domain
Restrict the key to only be able to use "Identity Toolkit API"
Is there anything else I should do here?
My application should be the only one able to use my credentials to access the Firebase API.
For any app where you access a cloud based API directly from within the client-side application code, that is going to be a myth. The closest you can get within Firebase these days is with App Check, but that isn't available for Authentication calls at the moment.
Part of the reason for this is that the authentication API is quite well protected on its own already, and most abuse will actually not affect you as a developer very much. E.g. (ignoring phone auth) there is no charge for account creation, sign in, and any other operations.
I highly recommend checking:
Is it safe to expose Firebase apiKey to the public?
The documentation on API keys in Firebase.
The documentation on Firebase's security rules, which is how you can protect the Firestore and Realtime databases, and files in Cloud Storage.
The documentation on Firebase App Check, which reduces abuse for Realtime Database, Cloud Storage, Cloud Functions, and Firestore at the moment.
More of these previous questions on allowing only you app to access Firebase

Where should the OAUTH2.0 Server be for Actions on Google/Firebase

Referring to - https://developers.google.com/actions/identity/oauth2-code-flow Im using Actions SDK which implies Im using Firebase Functions for the fulfillment handling.
Im storing information in Firebase against the UID I got from FirebaseUser.getUid() in an Android app. So far so good.
I've setup a mock OAuth2.0 server and this seems to be happy exchanging tokens.
However later on in the documentation it states:
"Your service's API endpoints use the access token to identify the user on whose behalf Google is making the API call, and to verify that Google has authorization to access the endpoint on the user's behalf."
My fulfillment however is in Firebase Functions. So...
Do I need to get my FirebaseFunction to get the User ID from the OAuth2.0 server? Do I need to setup an OAuth2.0 server in Firebase Functions? Where does the OAuth2.0 server sit? And how do I get my Firebase Function to get the same User ID as reported by Android?
First - you're starting with a small misconception. Actions on Google and the Actions SDK do not require Firebase Functions for fulfillment. Firebase Functions do make it easier - they provide the publicly accessible HTTPS endpoint that you need for a webhook, but if you have your own server (with valid SSL certificate) or if you want to use AWS Lambda or something similar, you can certainly do so. And if you want to use a language besides JavaScript, the JSON protocol used is documented (although sometimes not clearly).
To answer your questions:
If you need the UserID in your webhook, then yes, it needs some way to get that UserID given the access token it will be handed. But how you do this depends on how you implemented your OAuth server and token. For example:
If you used signed JTWs as your token, then the UserID is part of the JWT and all your webhook needs to do is extract this and verify the signature and timeframe on the JWT are valid. You don't need to contact any other server to do this.
If you're storing the tokens and corresponding user info in Firebase or in some other database or data store - just read the token from your webhook!
You certainly can create another HTTPS endpoint you can use to validate the token and get the info from it - this is what Google does, for example.
Your OAuth server does not need to live in Firebase Functions any more than your webhook does. It might be a good place for it to live (along with the authentication page on Firebase Hosting), but it isn't required.
Your OAuth server can sit... anywhere. Well, anywhere public on the Internet with a valid SSL certificate anyway.
This last point is exactly what account linking is all about. You need to make sure that, when they authenticate against your server, you get the UserID that is "reported by Android", whatever that means in your context (but see my update below). Once you have this UserID, you need to make sure it gets associated against any of the tokens that you issue for this user, and you need to provide a way for your service to get this UserID from the token.
How you do this is up to you, and depends on the rest of your architecture and what you're trying to do with it. The Google Assistant doesn't care - it has its own notion of a UserId which is separate from yours, so to identify the user with your UserId, you'll use the token that it hands you.
Update
You raise a good point in the comments about the statement "The user ID on Android devices will also be the same as the user ID on a Google Home". This is true, but talks about the anonymous cookie-like UserID that is available through the Assistant platform only (which is why it is in the section on Anonymous User Identity). It doesn't talk about any ID that you can get through other Android apps. To associate the ID you get through other apps to the Assistant's ID, you need to use Account Linking as described on the following page.
If all you need is a consistent way to track a user that visits your Action multiple times, and you want that to be consistent on any Assistant platform (Google Home, Assistant for Android, or Assistant for iOS), then you just need to use the UserID that is provided through the API/JSON. You don't need Account Linking or an OAuth server. But this is not a Google ID or the Firebase ID, it is a anonymous UserID that is valid on the Assistant platforms only (and then, only within certain conditions if the user does not reset it).
Update 2 To be clear about OAuth and JWTs:
You ask in the questions "Where else can I get the JWT?"
In short - you build it yourself.
Remember that, if you are providing an OAuth server, one of the things you need to do is to issue auth tokens and refresh tokens. Those tokens can be anything you want - the only criteria is that your webhook be able to take the token and, somehow, get the information it needs out of it that ties it to a user.
But you are responsible for putting that information in there in the first place.
So when the user logs in during account linking, you might use Firebase Authentication to log them in. Once you've done so, you can get a Firebase ID and/or a Google ID for them. (After all, they've logged into your OAuth web page - you have to know something about them.)
After they log in, you're redirecting them to some place Google has asked you to, and you're including a token as part of that. That token can be the JWT that you're creating, and in that JWT, you can include the ID information you have from their login.
(And, again... it doesn't have to be a JWT. It can be anything you want. The only requirement is that you be able to validate it and use it to get the information you need.)

Is Firebase really Secure?

I'm looking into using Firebase for a project that's otherwise a static site with js. Is it possible to secure the connection to the database in a static site? Wouldn't all security rules, the end point url, etc all be exposed in the js code letting the user make any requests they want (good or bad).
The short answer is yes: by authenticating your users and writing security rules, you can fully restrict read / write access to your Firebase data.
In a nutshell, Firebase security is enforced by server-side rules, that you author, and govern read or write access to given paths in your Firebase data tree.
Firebase security rules are JavaScript-like expressions: easy-to-write expressions that have access to the credentials for the connection, and the view of the Firebase data tree as it exists, along with pending changes on write.
In most cases, your client-side logic, templates, assets, etc. will be static and public. What you're really looking to secure is user and application data, and this is where Firebase Authentication (whether using custom Firebase authentication tokens or Firebase Simple Login) comes in. Firebase Authentication is essentially token generation - taking confirmed, identifiable user data and passing it securely to Firebase so that it cannot be spoofed. This confirmed credential data is then made available in your security rules.
Check out https://stackoverflow.com/a/20842986/879295 for an example, and the Firebase Security Quickstart Video for a great overview / starting point.

Resources