API key is revealed via request url, how to deal with it? - reactjs

I have seen a similar question like How to solve API key is visible on request URL problem?, but I don't think it's applicable to my use case.
I'm using Firebase authentication for my application (React app, served from NestJS back end) and notice one thing, it exposes Google Cloud API key via request URL. The current authentication flow is:
Using OAuth2, the front-end makes a call to Google Identity Platform using Firebase SDK to retrieve login information (display name, ID token, etc.)
The front-end makes a call to NestJS API to validate the login information using Firebase Admin SDK and create HTTP only cookie to preserve authentication state.
As far as I know, the React App requires access to API key so Firebase can be implemented. There is no way to bypass that requirement. Even if a key is hidden in .env file, the API key is still revealed via network tab. In some cases, let say if I forget to handle exception of a signInWithRedirect() (or any other Firebase functions), the error is raised (Uncaught Promise: requestUrl/apiKey="My Key") is shown in console, so it's even worse.
I'm not certain if I misunderstand something regarding the whole implementation and authentication flow. If it is, then please correct me on that. If not, please let know how to solve this issue.

It appears in the case of Firebase, exposing API key is fine. However, this is only due to how Firebase works, not because exposing API key in general is safe. A more detailed discussion can be found here: Is it safe to expose Firebase apiKey to the public?
I'm using Google Identity Platform, not Firebase, but Google Identity Platform uses Firebase and Firebase Admin SDK too so I believe this is applicable.
This matter is also mentioned in official Firebase instruction video. Kudos to user usr28765526 for mentioning this.

Related

How to restrict the access to backend API to be only accessed by the react app?

I am creating a public facing SPA web application using React js.
The backend for this application are the endpoints available under Azure APIM. I would like to restrict the access to these APIM endpoints in a way that they are only accessible from my react app.
As the react app will be rendered in the user's browser, I cannot have any IP restriction on my APIM backend inbound policy, as the application could be accessed from anywhere ( public facing). But if anyone gets access to the API url by inspecting the network traffic in the browser , my backend API's become vulnerable.
How can I restrict that APIM endpoints are only accessible from the react app ?
I have tried using CORS policy to allow my domain , but still tools like POSTMAN are able to access the endpoints.
The short answer is you cannot fully prevent people from hitting your public API endpoint on their own.
The longer answer is that you can put protections within your API config so that this isn't a concern. If all requests need a valid user authentication token, for instance, it doesn't matter if that valid request comes from your React UI or an errant user's terminal window. Check out some best practices on protecting your API endpoints, and it will hopefully answer your question.
You can't. At best you can obstruct the user by making it harder to replicate a proper request to your API. Ultimately there's no way to identify whether or not a request came from a browser or some other tool though.
It's up to you to construct the API in such a way that the user can't abuse it by limiting the user to only perform actions that they should be allowed to make. If you are concerned by a user overloading your API you can add a policy to APIM to apply rate limiting (e.g. by IP).
It not be possible to prevent attackers from inspecting HTTP traffic and the vulnerable calling endpoints.
You should implement authentication controls on API. Whenever a user opens a new session on you SPA, the API grants that user a token that is valid for a fixed amount of time (~30 mins). Ensure that the API checks if that token is valid for each request.

Where should I implement firebase authentication?

Im watching this tutorial that uses the firebase client library in cloud functions to authenticate users. I am starting to doubt wether this is the right approach. Should I do all the authentication in the react app instead? The tutorial explains that the benefit of doing everything server side is that it decreases the amount of things the user has to download to run the application.
That being said, Im having difficulty getting the client library to work with typescript which makes me just want to scrap it. How should I proceed?
It is generally better practice to host authentication (and especially authentication logic) in the back-end, if not for performance, definitely for security reasons.
That said, you can avoid using cloud functions for this authentication with firebase! Here is an alternative super simple video tutorial you may like instead from Fireship: https://www.youtube.com/watch?v=zQyrwxMPm88. The Google Firebase YouTube channel also has many videos on the subject.
Cloud functions are useful for when you want parallel action to be taken in the back-end during or after login, while the useAuthState() react hook is great for when you want parallel action to be taken in the front-end during or after login.
so my view on the best approach to solve this on Firebase is to either:
A) Use the Auth Firebase SDK for your client to create users and sign in users,
B) Do it with the Auth REST API
The end result is the same, you get your users into Firebase and you can sign them in and get their auth tokens. The SDK runs on the client, the REST API runs on the server. Once that's done, you can use the user token and pass it to cloud functions to do whatever you need and check the token validity and permissions server side.
On the cloud functions you're supposed to use the Admin SDK, not the client SDK. And the admin SDK has all privileges. For a more specific reason why you SHOULD NOT use the client SDK on cloud functions, is because it keeps state. So 2 users calling your cloud functions, using the client sdk server side, would result in the same user token, which is an error.
I hope I've solved your problem?

Securing a React frontend and with Python API using AWS Cognito

I'm considering using AWS Cognito as a user management system for a single page web app I'm building using React along with a Python REST API backend (Pyramid). I'm struggling to see how all the pieces fit together for my architecture (the docs don't seem to be helping me). There are many great examples of how to implement authentication into the frontend using JS. My issue is how to integrate this authentication into my backend REST API.
In my current hand rolled user management system, the frontend calls the REST API on sign-in and is given a token which is passed to API again for every subsequent request. I'm then able to use ACL's on my API functions, check permissions to access resources, etc. If I were to use Cognito and perform the authentication on the frontend (as many examples do) how will my backend know if the token is valid when it receives it with a request? Surely I wont have to call Coginto from the backend to verify this for every request? Also how can I perform checks for information such as 'is this user in the admin group' if that group is defined within Cognito? Again, calling out to Cognito for every request seems very heavyweight and cumbersome.
I did see one example where a list of valid tokens was exported from Cognito as a JSON file and kept on the backend. This seems horribly static when users could be added and removed regularly.
Is Cognito really suitable for my use case? Some high level guidance and pointers to any relevant examples and docs would be greatly appreciated!
When authenticating with Cognito, the user can have 3 tokens:
Refresh
Access
ID
For python, boto3 can interface now with Cognito. There's also this python lib wrapper: warrant, to make it easier.
Once you have the token, it is possible to pass it to the API (eg: access) and it can be checked on the server side with python-jose, as per AWS docs
To pass the token, an example pyramid /login implementation can keep the information in the session before setting the request response:
request.session['my_token'] = str(a_token)
The default cookie session factory works, though it warns that the token is not sent encrypted.

Google Cloud Pub/Sub Publishing from Browser - How does Auth work?

I have a requirement to use Google Cloud Pub/Sub API directly from Browser ( similar to GA script). I was wondering how can in handle Auth without requiring going through a back-end server.
I want to invoke the Cloud Pub/Sub API directly from the browser. I tried and it says i need to authenticate first , my issue is how to secure the Auth Token.
Is there any javascript library that is available which i can use in Browser ( not backend) to invoke the Google Pub/Sub API.
Thanks in advance
The general approach in Javascript for authorizing and making authorized requests to Google APIs is shown at https://developers.google.com/api-client-library/javascript/samples/samples#AuthorizingandMakingAuthorizedRequests -- it's not specific to the Cloud Pubsub API, but it should work for all Google APIs. Similarly, https://developers.google.com/api-client-library/javascript/start/start-js for general Javascript access to Google APIs.
This is quite an old topic, but I've been recently assessing if it's possible. The simple answer is - yes, it is possible to send messages into PubSub topics directly from a browser application. The solution is as follows:
You need to post a message via REST API using fetch()
You need to send the Authorization header
Authorization header has to contain oAuth2.0 token identifying the user; it can be an anonymous authenticated user or fully authenticated, using firebase authentication library for example.
To have all three above working perfectly, you'd have to write a lot of code. It is not practical at all and architecturally not nice. Unless you absolutely need to do it that way, not another (I can't see why though), the simplified but involving a bit more components solution is as follows:
Authenticate user in-browser via firebase - can be either anonymous or full user
Do simple GET or POST to your cloud/firebase function with the required payload
In function validate the incoming request which will have authenticated user token
If validation is good then publish message into the topic
This way it's still secure, much more maintainable and clearly separated into functional components. Less code, a bit more infrastructure.

Google App Engine: Endpoints authentication when custom auth or Open ID is used

I recently got started with Google App Engine. I intend to use Flask to serve web pages and the Endpoints API, preferably with the Endpoints-Proto-Datastore for everything else.
From the beginning, non-Google Authentication mechanisms on GAE seem like they need some work. I'd appreciate any light shed on issues I've found so far:
Custom Authentication
If you can write an Open ID provider as part of the app, use something like Python-OpenID and also implement a consumer in the same workflow so it appears like regular login. This way it integrates nicely into what the GAE Users API provides.
I'm guessing if this is done right, users.get_current_user() will work just fine.
If you want to skip writing your own OpenID provider and instead write an email/password auth system using Flask-Login integrating with NDB, that should be alright too. However, one puzzling bit of info in the GAE documentation says I can instantiate a user object like so:
user = users.User("XYZ#XYZ.com")
However, (there is no user.put() method here) a users.get_current_user() still returns None. So what would the use of constructing the user object ever be?
Endpoints Authorization
On including a user=required in the method decorator for an Endpoint-Proto-Datastore rolled API, OAuth seems to work right away - all you have to do while testing it in the APIs explorer is to turn on the OAuth 2.0 switch and pick a valid Oauth 2.0 Scope. So does that mean that if we implement a OpenID provider that integrates with the Users API correctly, it won't be sufficient to use the OAuth magic of Endpoints API?
Here too, it seems like constructing a user object will not help satisfy the authentication requirement.
How would custom authentication / another OpenID implementation work with Endpoint API authentication/authorization?
I wanted to not use oAuth, but a simpler form of Authentication with user/token.
So what I've done is create a custom ServletFilter that maps to /_ah/spi/* and intercepts login information from the HTTPServletRequest there, if it is an Endpoint-API-Request.
Seems to work thus far, but am not really sure if that is the way to go. But as I've found no examples for non-oAuth-Auth anywhere, that's currently my best shot.
Would love to get some best practice hints from #bossylobster or #Dan Holevoet.

Resources