Subscription based iOS app I'm building uses Cloud Run service invoked via HTTPS request.
How can I make sure that the request can only be invoked by app owners(from the app)?
I've looked at Google Sign-In authentication, but I don't think it is applicable in my case as only those subscribed to the app should have the access, not just those with Gmail account.
I think without a Google Sign-in involved, your question has nothing to do with Cloud Run and can be generalized as:
How to send requests to to a backend app only from its mobile app?
So I'll answer that.
You'll find out that you need some form of "authentication" to prove that you're on a mobile app as a "user". To achieve that, you need some form of sign-in.
You may try to ship a secret (like a token or private key) in the application and use that to authenticate, but this will be susceptible to:
exfiltration of the private they from the application bundle through reverse engineering
applying a man-in-the-middle attack to the HTTPS request (and therefore the token) by trusting a root CA on the device and using e.g. mitmproxy to decrypt the request as plaintext.
In reality, there's no way to fully secure iOS/Android <=> backend communication that. Even the largest apps like Twitter, Instagram etc have their APIs reverse engineered all the time and invoked from non iOS/Android clients as the requests can be spoofed.
If you want to authenticate your existing users, you should figure out how these people login to your app. This could be simple username:password in Authentication: Basic [...] header, or something more complicated like OAuth2 which is what apps like Facebook, Twitter implement under the covers for their mobile apps.
Then you would validate that Authentication header in your Cloud Run application code yourself.
So again, I don't think this is a problem specific to Cloud Run, or any cloud provider.
If your goal is for your API to only be called when your users are authenticated in your app, I would recommend implementing one of the two solutions described on this page:
Using Google Sign-in or Firebase Authentication
Related
We have gone through the authentication overview but it doesn't answer our question so reaching out to the experts here.
Our web application once loaded on the browser for a user makes requests to our service on Cloud Run. We would like to secure our backend service so only our Domain can access this and not some user using Postman, or a shell script to access / update data.
end-user-access auth
Because the user doesn't have to be always signed in, we would like Cloud Run to respond to the requests, even if there's no auth token present. This eliminates the end-user access to service option for us.
service-to-service auth:
Because it is the browser, and not another service in our GCP platform that's making the request, even this option doesn't work for us.
The user data in our backend is secure, because those end points require Auth tokens, however, pages that don't need auth token are insecure, and could be vulnerable to DDOS or bot/scraping attacks.
How can we secure our Cloud Run service so only calls from our Web Application are responded to and not others?
You can't be sure that the web application is the sender of the request. Indeed, in the web environment, you send your code on the client side. From here, the users (good or bad) can go into your code and understand how it works, what are the header of the request, how these headers are built,...
Complex, and inefficient things can be imagined... Maybe, the best way is to plug an API Gateway and to perform rate limit for the users. Like this, even if the user uses an automated thing, they will be limited. I wrote an article on the Cloud Endpoint Rate limit. Not sure that is the best product for this, maybe Apigee can fit better your requirements.
EDIT
What I would like to say in the first paragraph is "it's not possible with Cloud Run and with any other web technology".
I have a Django application that currently stores user credentials and performs authorization and authentication. I am in the process of breaking off the front-end into an Angular SPA and converting the backend to a REST API. My Django API will live as an Azure API app protected by Azure API Gateway. I would like to remove the authentication piece from Django and allow users to sign in using OpenID Connect through either Google or Microsoft Account. What I would like to happen is this:
When a user visits the site, assuming they have never registered with my app, they will have the option to sign in with their Google account or Microsoft Account. If the user decides to sign in using their Google or Microsoft account, (this is where I'm confused and why i'm posting here ... ) I think what happens is the API Gateway performs the authentication, generates a JSON Web Token (JWT), and sends that token back to the Django API. Django receives the JWT, decrypts it, and checks to see if there is a user account matching the email address in the JWT. If there is not a user account, Django will add a user to the user accounts table (not storing a password). If there is a user matching that email address, then Django allows the user in.
All that said, I guess my question(s) are:
Should I do the authentication at the API Management Gateway or should I do it at the Azure Web API?
Can I use Django's built-in authentication system to do what I want or is that not needed?
Am I over-complicating all of this? Is there an easier way to do this? All this seems like a lot of work.
Is OpenID Connect what I should be using (instead of Oauth2)? I have no experience with either.
Azure API Management does not actually provide any kind of JWT issuing mechanism, so you'll have to implement that yourself. The end points for doing that may or may not be exposed via API management.
What possibly gets you confused is the fact that the APIm Portal supports various indentity providers, like Twitter or Google, to sign up for the API. But these are not your application users, these are for the API Portal Users.
What you can do with the APIm Gateway is to validate subsequent calls to your backend API that the supplied JWT token is valid (using the <validate-jwt> policy).
I have various RESTful Web Servicesin App Engine, which are secured Google Account authentication:
<security-constraint>
<web-resource-collection>
<web-resource-name>Authentication required</web-resource-name>
<url-pattern>/api/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
Upon hitting these Web Services via a browser client, I'm redirected to the Google Accounts login screen where I authenticate myself first before proceeding with the REST call.
However I now need to run these web service via a command line scripts as part of automated IC run. Therefore I do not want to be prompted for a browser login every time. Preferably I would like to put the Google username and password in a encrypted file on the IC server and let it call the Web Services without any human intervention. As far as I can see there are several options:
manually logging in via the browser and then saving the access token to be used in the command line script. However when the token expire I would have issues.
obtain a access token via Service Account p12 authentication. This seems to only work for accessing Google APIs such as BigQuery and Cloud Storage, not your own code.
wrap my Web Service within a Remote API which I have yet to experiment with.
Based on my current understanding, it seems there is no way for a Google Account authenticated custom written Web Service to be accessed by a non-human user. Is this correct?
Since you are interested in interacting with RESTful web-services programmatically (without human intervention), we are essentially talking about securing a REST API.
There is a plethora of resources on this matter throughout the internet but the gist of it is:
you should use SSL and sessions or OAuth to secure your endpoints.
Depending on how far you are in the current project, you could consider making use of Cloud Endpoints, there you'll have the option to use OAuth2 (and have DDoS protection), as well.
Hope this helps.
I managed to get this to work in the end by:
Switching off the web.xml security-constraint so that the API doesn't redirect to Google Login.
Modifying my API to take in a Oauth2 token in the Authorization header instead.
Validating the token based on the code sample here: https://github.com/googleplus/gplus-verifytoken-java
I didn't go with Cloud Endpoints, but Jersey + Dropwizard components instead. Dropwizard has built in Oauth2Provider which I simply implemented a Authenticator class and it works.
We need to implement an authentication/autorisation web service and I am not sure if we should use the Oauth protocol in our situration.
The background of the story:
We have some J2EE web applications in a jboss server. Authentication and authorisation of the applications are implemented by JAAS and deployed in this jboss server.We want to add some new web applications that are implemented in other languages and deployed in other servers. To re-use the authentication/autorisation mechanism in the jboss server, we need to implement authenication/authorisation web services for the new applications.
So here comes some thoughts:
Is it necessary to adapt the OAuth protocol for the authentication/autorisation web service ?
As I know, OAuth2 is use to grant access to functionality, user's data, etc.. without giving the password to the 3rd party app. This is not really our case as we actually own all the applications, although that the newly apps are not in the authentication server.
Another choix is to implement the login webservice et then return the new apps a ticket/token to use later.
In another way, with OAuth protocol, newly apps do not involve in user's login/passwords, which seems to be nice...
Do you have some ideas ?
OAuth works on the concept of "ResourceOwners (Which gets the user credentials and enables the client's access to the server's apis)", "Server (owner of the resources) and the "clients (who want access to the server resources but doesn't have access to the credentials).
OAuth is just one way of providing security to the resources which means it is not necessary to have it for all "authentication/autorisation".
In your case I dont think there is a need of full fledged 3-legged OAuth however you can still go ahead with 0-legged OAuth or some other approach. Also, I don't understand what did you mean by "newly apps do not involve in user's login/passwords" as this is completely composite to what OAuth is meant for. User generally provide the credentials when they login into the app and then that login call ensures that the clients have access to the server resources.
If you just want to "return the new apps a ticket/token to use later" then OAuth is not for you as it is more than just providing the token for later use. Also, token in OAuth is for server's api access.
I'm working on an iPhone app that uses xAuth to login to Twitter. The app also communicates with my own web service. Rather than maintain a user model inside the web service, I'd like to just allow anyone who's already authenticated via Twitter to make requests.
The high-level use case is this: the user logs into and interacts with Twitter through the app. They can also interact with my web service through the app. The web service itself never interacts with Twitter. Instead of maintaining a separate authentication system on my side, I'd like the server to say "OK, if Twitter says you're #joshfrench then you can have access."
I'm not sure how I should validate requests on the server side, though. How would I pass some proof of authentication from the mobile client to my web service? Can I send along the existing Twitter token and verify it from the server? Or somehow sign the request with my Twitter app's credentials? Is this even a valid use of OAuth?
If you store your twitter app key and secret on both he iphone app and your server, and then somehow transmit the user's oauth token (also called "access token") key/secret from the iphone app to the server, then you can do the same type of api calls from the server.
consumer = OAuth::Consumer.new(app_key, app_secret, …)
access_token = OAuth::AccessToken.new(consumer, user_key, user_secret)
response = access_token.get('/stuff.xml')
So, is it Okay to transmit that info from the app to the server? If you do it securely, and it's within the user's expectation for how the app behaves, then it's a perfectly fine use of oauth.
It's possible that it's not allowed by Twitter's terms of service -- I could imagine there being something that says you can't transfer a user's access secret across the network, or some such thing. (total wild speculation, I don't think it's particularly likely that that's the case)