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

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.

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.

Multiple Auth Providers with AppEngine, Webapp2, and Cloud Endpoints Proto Datastore

I'm working on a webapp that will allow users to authenticate using simpleauth. For now I will be supporting Google and Facebook. Other than logging in and out (using webapp2), the webapp will consist of Cloud Endpoint APIs. The clients will be web, Android, and iOS.
My questions is, using Endpoints Proto Datastore, can I have user_required=True and call endpoints.get_current_user() to get my user from an #Model.method if the user's auth provider is Facebook (or any of the other supported OAuth2 providers? If it is not possible, does that mean I should not have user_required=True, and should instead get a permanent user id from the provider given the OAuth2 token and keep it in the datastore, generate my own auth token for that user, and then pass that token to each request?
EDIT: Instead of passing the auth token around, would it make sense to have an authenticated user request an "API token" that they can pass to the API methods? Would this token have to be included in the POST or GET body, or can it be put in a header/cookie (I saw some questions elsewhere on SO regarding headers and cookies with Cloud Endpoints, but it's been some time since then). This is all assuming that non-Google auth won't work.
This answer is not going to directly answer your question but should give you a good idea how you can implement authentication in a safe way. I've implemented something similar recently and spent quite some time figuring out which is the best way to do authentication with Google AppEngine environment.
Google supports OpenId Connect protocol. Facebook's implementation should be very similar according to Getting Started with OAuth 2.0 book. I will focus more on Google's implementation, as I am more familiar with it but the concepts should be very similar when using other OAuth providers.
OpenId Connect will give you an id_token, after successfully authenticating the user. It will also give you an access token. Access token is something that should be kept a secret. Never send it over the wire. Id token on the other hand is very handy. It contains some information about your user, and it's encrypted so it doesn't expose any information about the user "just like that". You'd have to crack the id_token to find out anything about user. In the unlikely event that it gets cracked it doesn't expose anything critical about the user. What you can do you can store it as a cookie and then use it in all subsequent requests to verify it the user by checking if there's an access token that matches the id_token. The only drawback is that id_token is quite long - it takes around 650bytes. That would mean that every http request carries that payload. If sending that much information is too much for your use case you can send only first few characters, maybe 12 or so and then match just the first part. The id_token has can also be useful when analysing your data. It will show up when analysing http requests but will not reveal any information about the user and you can still differentiate requests that came from different users.
Also on a side note, don't try using AppEngine's users service as it doesn't work very well with any kind of custom authentication.
Hope this gives you an idea and puts you on the right track.

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