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.
Related
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.
Im developing a backend for mobile which is using Firebase for authentication and authorization. When the mobile ends the authentication process it sends through http methods to my backend an idToken signed by Google, which then I verify the signature and payload of the provided idtoken.
Is there a way to get the idToken from Google Firebase Console?
At the time I only figured out how to get it from mobile through a method called getIdToken for Kotlin. I can't keep getting the token this way, I need to do it without the mobile.
Thanks!
There is no server-side API to get ID tokens of your users from Firebase Authentication. You will have to get it on the client, and pass it to your server to be verified, exactly as you already seem to be doing.
That is also the process that the Firebase services and SDKs themselves follow, so you might want to reconsider whether this is feasible for your use-case too, or edit your question to better explain why it isn't possible.
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.
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.
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.)