This question already has answers here:
How do I securely use Google API Keys
(2 answers)
Closed last month.
According to https://developers.google.com/maps/documentation/javascript/tutorial#HTML5 ,
it seems I can add the following tag to my html and start using maps js API.
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
But this will reveal my API key.
After searching on google and browsing answers on stackoverflow, I feel that maybe there is no need to hide this API key. I just need to set the referer when I create the API key on google, as explained in
https://stackoverflow.com/a/2256312/1316649
So, even others know my API key, they cannot use it from another domain. Am I right?
But google says you shouldn't embed API key in code:
https://support.google.com/cloud/answer/6310037
So, do I need to hide API key when using google maps js API? If so, how?
Update: By 'API key', I meant browser API key.
You can create multiple API keys with different restrictions to use them safely. For embedding a map, the Google Maps documentation has instructions for creating a correctly restricted API key so that it cannot be abused for other purposes at Get an API Key - Restricting API keys. It's OK to include a restricted API key in your source code, because you cannot embed a map properly without doing that anyway.
If you need server-side API access, you can create a second API key with less restrictions. That one should be kept secret.
While the above answers are helpful, none of them addresses the following vulnerability:
Once a user has access to your API key, even if they are restricted to using it only from your domain, they can still use it as much as they want. In the crudest sense, this could mean a million page refreshes (and map loads) in a very small amount of time, consequently putting you over your usage quota.
I haven't come across any solutions that address this issue. Unless I'm missing something...?
Relevant usage limits for google maps javascript api here.
The link that you posted that says you shouldn't embed API keys in code is related to Google's Cloud Platform. You are fine to leave your API key for Google Maps in your code.
To hide an API key for any service:
Design a web server that will accept requests for the third party service and proxy requests to them.
Design your interface to make requests to the web server that you designed in step 1.
Store the key on the web server you built in step 1, and apply authentication, authorization and rate limiting to the 3rd party proxied requests.
The 3rd party libraries that you use might to build and interface in step 2 might force you to use certain hosts or might force you to include an API key. For the first problem, you'll have to either edit their library code, or provide the 3rd party client library with a different http request library, like redefining the fetch() function in javascript for example. For the second problem, just add a garbage key and your proxy server can ignore it and re-write it with the real key.
Benefits:
Hide your keys.
Track who, what, and when for requests and responses. You could do this other ways though.
Could add a layer of caching to the service to speed up requests that other users have made before, provided that their terms of service allows it.
Caveats:
Because users will be making requests pretending to be your server, you are accepting a security risk. If the user intentionally makes maliciously formatted requests, they are doing so while appearing to be your server. You can however log all requests if you want to audit them later.
It takes more than a couple seconds to build and configure the proxy server with all the security you require.
You now need to handle all of these web requests which may be a lot of traffic.
You may want to intercept the responses the server returns in case it returns the key in the response body during in an error or otherwise.
You are adding another link in the chain and it will make the service slightly less reliable.
Mentions
I wanted to mention that this is essentially what "#OLTO and SUGI-cube Project" was trying to demonstrate in their answer and what #Brandon Miller was suggesting as a solution in a comment.
No need to hide API key, you just have to make it useless,
You can simply use key restrictions on the google API console.
from google API console choose:-
credentials
choose your API key or create a new one
Application restrictions
HTTP referrers (websites)
and then add your Website restrictions
I would recomend restricting your API keys to only be used by the IP addresses & referrer URLs that need them: By restricting the IP addresses, referrer URLs, you can reduce the impact of a compromised API key.
You can specify the hosts and apps that can use each key from the console by opening the Credentials page and then either creating a new API key with the settings you want, or editing the settings of an API key.
This should help you to secure your API keys.
Jeff
The two most accepted ways I have seen are to either use the [#googlemaps/js-api-loader]1 Or to - and this is important - restrict your keys the way google tells you to.
Hello there,
Even if it's too late to post an answer I believe this would help the community, so i have worked out a solution that will hide the script tag from the DOM, I managed to do it by deleting the script tag after loading the script OR if it were an error while loading it,
So here is the proposed solution and I'm happy to hear from you if it doesn't fit:
<script>
const deleteMapScriptTag = () => {
document.body.removeChild(
Array.from(document.body.getElementsByTagName('script')).find(
(item) =>
item.src.includes('https://maps.googleapis.com/maps/api/js?key=')
)
)
}
</script>
So that part will search for the google maps script tag and remove it from the document, and we will call it after the
onload, onerror
events provided by the script tag as demonstrated below :
<script onload="deleteMapScriptTag()" onerror="deleteMapScriptTag()"
src="https://maps.googleapis.com/maps/api/js?key={YOUR_API_KEY}&libraries=places"></script>
this will remove the script tag from the DOM as soon as it loads or fails loading, preventing users from inspecting the file and acquiring your key.
Although removed from the DOM, the original script tag (and therefore the key) will still be visible when viewing the page source.
Additionally, the full URL of the script can also be inspected via the Network requests panel in developer tools which also exposes the API key.
You need to hide API key
You need to hide API key when using google maps js API. It is not enough for you to set the referer.
I have local web server on my PC and can change my hosts file, So that I can spoof domain name of my HTML as your domain.
If you reveal your API key in your HTML, someone might access Google map with that key. This could mean a million page refreshes (and map loads)!
This is bad example from Google.
<script defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
How to hide API key from HTML
I use Environment Variables and CGI to hide my API key from HTML as follows.
1. set Environment Variables
I set Google Maps API key in Environment Variables and passing it to my CGI scripts.
nginx + fcgiwrap are running on my server, so I set API key in my fcgiwrap.conf like this.
fcgiwrap.conf
location /cgi-bin/ {
........
fastcgi_param GOOGLE_MAPS_API_KEY YOUR_API_KEY; <= SET YOUR API KEY HERE
}
2. make CGI script
I made python CGI like this. This is same as src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY in SAMPLE of Google.
getapijs.py
#!/usr/bin/python
# -*- coding: utf-8 -*-
import requests
import os
url = 'https://maps.googleapis.com/maps/api/js'
key = os.environ['GOOGLE_MAPS_API_KEY'] # get Environment Variables
mysrc = url + "?key=" + key
response = requests.get(mysrc) # get src from Google Maps url
print("'Content-Type': 'text/javascript; charset=UTF-8'") # header for HTML
print("")
print(response.text)
3. call CGI from javascript
call your CGI from window.onload. This is same as <script defer ... &callback=initMap> in SAMPLE from Google.
main.js
function initMap() {
var uluru = {lat: -25.344, lng: 131.036};
var map = new google.maps.Map(document.getElementById('map'), {zoom: 4, center: uluru});
var marker = new google.maps.Marker({position: uluru, map: map});
}
window.onload = function() {
fetch("/cgi-bin/getapijs.py").then(res=>{
return res.text();
}).then(mytext => {
eval(mytext);
}).then(() => {
initMap();
}).catch(() =>{
// error handling
});
}
4.read main.js in your HTML
set <script src="main.js"></script> in your header section.
index.html
<!DOCTYPE html>
<html>
<head>
<style>
/* Set the size of the div element that contains the map */
#map {
height: 400px; /* The height is 400 pixels */
width: 100%; /* The width is the width of the web page */
}
</style>
<title>Hello World</title>
<script src="main.js"></script>
</head>
<body>
<h3>My Google Maps Demo</h3>
<!--The div element for the map -->
<div id="map"></div>
</body>
</html>
My project requires me to get the list of connected users to the account.
I saw that i can do it using this
GET https://www.googleapis.com/plus/v1/people/me/people/connected?key={YOUR_API_KEY}
however, im having problems on how to supply YOUR_API_KEY
I tried this
https://github.com/EddyVerbruggen/cordova-plugin-googleplus
and was able to acquire the oauthtoken but it doesnt appear to be the api_key.
note : obj.idToken is always null so im only able to get the oauthtoken.
if someone could point me in the right direction that would be a great help.
Thanks,
Jay
There is some mistake in documentation. You need to use webApiKey param instead of webClientId. Look at GooglePlus.java in your Cordova plugin directory - how your JS params are put to Google Api.
I generated Browser API Key in Google Console and set referrers:
Then I go to http://afriflirt.com, open JS console in browser and run this code ("Google Maps Geocoding API" enabled for this api key in settings):
var apiKey = 'AIzaSyAGpR-mG46fDbmWjJwkZZHft_xvZ_dM3cA';
$.getJSON(
'https://maps.googleapis.com/maps/api/geocode/json?address=12345&key=' + apiKey,
function(resp) {alert(JSON.stringify(resp));}
);
in response I see this message:
This IP, site or mobile application is not authorized to use this API
key. Request received from IP address 113.180.75.109, with referer:
http://afriflirt.com/
If I remove referrers - API key start working, but this is not safe.
So it's a problem only when I set referrers. Tried different formats of referrers patterns, but nothing worked. Also tried to wait some time (as I saw "it may take up to 5 minutes for settings to take effect"), but it doesn't help too.
Please let me know if you have any ideas how to fix this.
According to the documentation, you need a server key for the geocoding web service.
Create a server key, enable it for IP address: 113.180.75.109, that should work in your example (but it isn't recommended to use a server key from javascript like that, use a browser key and the Google Maps Javascript API v3 Geocoding Service).
I am trying to use the javascript sdk to do an oauth login and access the google plus api. Basically the same code here: https://developers.google.com/api-client-library/javascript/features/authentication
In my firebug console, this is the url that is sending the api request to:
https://content.googleapis.com/discovery/v1/apis/plus/v1/rest?fields=servicePath%2Cresources%2Cparameters%2Cmethods&pp=0&key={key}
This is the error that comes back:
{"error":{"errors":[{"domain":"usageLimits","reason":"keyInvalid","message":"Bad Request"}],"code":400,"message":"Bad Request"}}
I have:
1. Added Google Plus Api to my project
2. Created oauth credentials
3. Setup my consent screen
However, I am still getting the error.
The reason is that you have the key defined in the request. As specified in the discovery API docs (https://developers.google.com/discovery/v1/getting_started#before_starting):
"The APIs Discovery Service provides only public methods that do not
require authentication. In addition, unlike the requests you make to
many other Google APIs, the requests you make to the Discovery Service
API should not include an API key. If you do provide a key, the
requests will fail. This behavior helps ensure that you don't
accidentally disclose your API key when distributing tools that are
based on the Google APIs Discovery Service."
So you can solve the problem by removing the key from your request entirely.
If you are using Google's javascript client to do this and the error occurs when loading further APIs, you have to unset the key first:
gapi.client.setApiKey( null );
gapi.client.load( "plus", "v1", function( apiresponse ) { ... } );
If another function requires the key later, you have to set it again.
To avoid setting and unsetting the key constantly, I load all the needed APIs before authentication, then set the API key and thus will no longer have the issue.
I am trying to find the location of cell towers using MNC, MCC, lac and CellID.
I have tried many api's such as opencell, combian etc. But none of them are free.
Is there any rest free API available, but for the moment I am using Google geolocation api.
I am sending request in javascript like this
https://www.googleapis.com/geolocation/v1/geolocate?key=xxx&homeMobileNetworkCode=410&homeMobileCountryCode=310&locationAreaCode=415&cellId=42&format=json
and all the time it return "Not Found"
I checked many places on stackover, but could not find good solution or hint. In addition is there any Free Api Available for getting operator name by using data mnc, mcc, cellid and lac.
In addition, I have also tried to use this link to get location but I could not as I can not find what parameter I need to pass and what should be the url I need to create.
Please provide me some guidelines to get location and operator name for specific tower by using information such as mnc, mcc etc.
Thanks appreciated
Google describes the geolocate API endpoint in their docs. You tried to do a GET request, but they say that you should use POST, with JSON-Formatted data:
Communication is done over HTTPS using POST. Both request and response are formatted as JSON, and the content type of both is application/json.
If you want to use the undocumented API from your link, the URL is http://www.google.com/glm/mmap and the POST-data is what is written in the function WriteData. See the Java Docs for DataOutputStream if you are unfamiliar with the output produced by the various write..-methods.
As for getting the operator name, there are free databases available for that (alternative 1, alternative 2; search google for more, there are plenty).