GAE Cloud Endpoints custom API public api key issues - google-app-engine

I've exposed a few APIs using go-endpoints. The APIs work fine, but what I'd like to do is restrict usage of the APIs to only a few referers. Since I'm not passing any authentication information, I do not need OAuth (actually, I really do not want to use OAuth as I expect anonymous users to utilize a front-end that uses this API... I just want that front-end and perhaps another one to use my API).
Apparently the way to do this is to make a Public API Key using the Google Developers Console (Project --> APIs and auth --> Credentials --> Create new Key).
I've changed my JavaScript to use this key, by passing it as a param: https://my-app-id.appspot.com/_ah/api/myService/v1/doSomething?key=key_from_developer_console
However, when I make the call, I get a 403 back with this error:
"Access Not Configured. The API () is not enabled for your project. Please use the Google Developers Console to update your configuration."
Well, initially I set the referer to my-app-id.appspot.com/*, which is only place I want my API to be used from. So I figured I'd remove it just to see, but I get the same issue.
There are some old posts here about having to enable Contacts API and Google + API. I tried that, and it didn't work either.
So what gives? There is virtually no documentation from Google on this Public API Key feature. This is really driving me up a wall...

I had this exact same problem yesterday. I decided to generate my own key and added in my own logic to check for the 'key' param from the request. I just added the self-generated key to my env_variables and it works. However, if you try to redeploy after taking this approach, you may still see the access configuration issues..at least I have still.

Related

AppEngine authentication through Node.js

I'm trying to write a VSCode extension where users could log into Google AppEngine with a google account, and I need to get their SACSID cookie to make appengine requests.
So I'm opening a browser window at
https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https://appengine.google.com/_ah/conflogin%3Fcontinue%3Dhttp://localhost:3000/
(generated by google.appengine.api.users.create_login_url)
The user logs in and is redirected to my local webserver at
localhost:3000/_ah/conflogin/?state={state}
Now I try to forward the request to my AppEngine app (since it knows how to decode the state parameter), so I do a request to
https://my-app.appspot.com/_ah/conflogin/?state={state}
basically just replacing localhost with the actual app.
but it doesn't work, presumably because the domain is different. I assume this is on purpose, for security.
Is there any way I can make this work ?
Not ideal, but the only solution I've found is to have an endpoint on my GAE instance that does the redirection. Then I can set that as the continue url, when I'm starting the authentication process
https://accounts.google.com/ServiceLogin?service=ah&passive=true&continue=https://appengine.google.com/_ah/conflogin%3Fcontinue%3Dhttps://my-app.appspot.com/redirect?to=http://localhost:3000
I think you should center the attention on the protocols you are using, since it’s known that the cookie name is based on the http protocol (HTTP : ACSID, HTTPS:SACSID), and that’s the security perspective till this point for me.
Having the error you are facing now would be helpful to understand the problem better. Also, how are you performing the call to the API and the code you are using would be helpful too.

Serve REST-API data in web-page without exposing API-endpoint

I am beginner in MEAN stack.
When invoking unauthenticated REST API (no user log-in required), API end-points are exposed in the JS files. Looked through forums that, there is no way to prevent abusers using the API end-point directly or even creating their own web/app using those end-points. So my question is, are there any way to avoid exposing the end-points in the JS files?
On a similar note, are there any ways, not to use REST calls on front-end and still be able to serve those dynamic content/API output data in a MEAN stack? I use EJS.
There's no truly secure way to do this. You can render the page on the server instead, so the client only sees HTML (and some limited JS).
First, if you don't enable CORS, your AJAX calls are protected by the browser, i.e. only pages served from domain A can make AJAX calls to domain A.
Public API providers like Google Maps protect themselves by making you use an API key that they link to a Google account.
That key is still visible in the JS, but - if abused - can be easily disabled.
There's also pseudo-security through obfuscation, i.e. make it harder for an attacker to extract a common secret you are using the encrypt the API interaction.
Tools like http://javascript2img.com/ are far from perfect, but makes attackers spend a lot of time trying to figure out what your code does.
Often that is enough.
There are also various ways to download JS code on demand which can then check if the DOM it runs in is yours.

Google Street View Premium Plan API - API server rejects your request

I'm trying to switch from basic Google Street View API to Premium. As such, when I'm using:
(space after https is added because I can't post more than two links in the post)
https:/ /maps.googleapis.com/maps/api/streetview?location=40.720032,-73.988354&size=400x400&fov=90&heading=235&pitch=10&key=MY_PREMIUM_API_KEY
I get an image with a Google watermark, which does not scale further than 640x640, same as when using a basic API key.
Okay, to use the advantages of Premium GSV API, I also need to make a digital signature. I've generated a secret key and signed my url (with dropped domain, as said in the tutorial) using python code from there: https:/ /github.com/googlemaps/url-signing/blob/gh-pages/urlsigner.py - it generates just the same signature as one on the Google website: https://developers.google.com/maps/documentation/streetview/get-api-key?hl=en_GB#premium-key
Finally, I add the signature to the URL:
(space after https is added because I can't post more than two links in the post)
https:/ /maps.googleapis.com/maps/api/streetview?location=40.720032,-73.988354&size=400x400&fov=90&heading=235&pitch=10&key=MY_PREMIUM_API_KEY&signature=MY_BASE64_SIGNATURE
However, this is what I get in return instead of an image:
"The Google Maps API server rejected your request. This API project is not authorized to use this API. Please ensure that this API is activated in the APIs Console: https://console.developers.google.com/apis/library?project=_"
It cannot be that API project is not activated, as basic API with this project & Premium key works. Any ideas, why does it happen and Premium image download doesn't work?
It appeared to be a purely technical problem, the quotas were exceeded.

Possible to access Piwik getVisitorLog through HTTP API?

I'm building some reporting tool. Ideally I want to avoid going through web server logs myself and use (some of) the power of Piwik.
The stuff I get from the visitor log would be a good start, this is at http://example.com/piwik/index.php?module=CoreHome&action=index&idSite=1&period=day&date=yesterday#/module=Live&action=getVisitorLog&idSite=1&period=day&date=yesterday
Unfortunately I can't find a getVisitorLog action in the HTTP API docs at
http://developer.piwik.org/api-reference/reporting-api#Actions (and it's also not an undocumented feature, method=Actions.getVisitorLog gives me
The method 'getVisitorLog' does not exist or is not available in the module '\Piwik\Plugins\Actions\API'.
Is there another way to get to this? Or should I write a plugin for Piwik?
Apparently it is possible through the Live plugin API:
http://developer.piwik.org/api-reference/reporting-api#Live
This works as desired:
http://example.com/piwik/index.php?module=API&method=Live.getLastVisitsDetails&format=JSON&idSite=1&period=day&date=2015-07-21&expanded=1&token_auth=XXXXX&filter_limit=100

How to use generated clientid with Google cloud endpoints for authenticating 3rd party users without redeploying app

In my case we work with other companies which would consume our APIs along with our internal javascript client. I think we need to create a web client id for javascript client. But when exposing APIs externally, is it correct to generate new web client id per company? If so do we have to update clientid each time and redeploy application?
I'm following this documentation and in their example client ids are hardcoded, if I need to give access to new 3rd party users, then I need to generate new client id for them but I'd expect to not redeploy application.
Update: I've created a feature request as per #Alex's suggestion below.
Unfortunately the docs at https://cloud.google.com/appengine/docs/python/endpoints/auth very specifically say, and I quote,
Because the allowed_client_ids must be specified at build time, you
must rebuild and redeploy your API backend after adding or changing
any client IDs in the authorized list of allowed_client_ids or
audiences
so it appears that your perfectly-reasonable use case is very explicitly not covered at this time.
I recommend you visit said page and enter a feature request via the "Write Feedback" link (around the upper right corner of the page) as well as entering a feature request on the Endpoints component of the App Engine feature tracker, https://code.google.com/p/googleappengine/issues/list?can=2&q=component=Endpoints&colspec=ID%20Type%20Component%20Status%20Stars%20Summary%20Language%20Priority%20Owner%20Log -- we monitor both, but with different processes, so trying both is best.
Sorry to be a bearer of bad news. For now, it seems the only workaround is to distribute to the other companies one of a bunch of client ids generated in advance (you can only change the valid bunch when you re-deploy, sigh) and perhaps add some extra, app-layer authorization check of your own -- exactly the kind of work endpoints should be doing on your behalf:-(.
You can use an asterisk as the client ID, that will allow any client to call it without redeploying your API backend. Not sure if this is a documented feature or not, but it works (at least) with both Python and Java.
#Api(name = "myapi",
version = "v1",
scopes = {"https://www.googleapis.com/auth/userinfo.email"},
description = "My flashy API",
clientIds = {"*"})
public class MyAPI { ... }

Resources