So I'm trying to use Google URL Shortener API in my app. Here's the class I wrote to make the HTTP call and retrieve the shortened URL.
public class GoogleUrlShortnerApi
{
//API Key from Google
private const string key = "-----------MY_KEY-----------";
public static string Shorten(string url)
{
string post = "{\"longUrl\": \"" + url + "\"}";
string shortUrl = url;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" + key);
try {
request.ServicePoint.Expect100Continue = false;
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = post.Length;
request.ContentType = "application/json";
request.Headers.Add("Cache-Control", "no-cache");
using (Stream requestStream = request.GetRequestStream())
{
byte[] postBuffer = Encoding.ASCII.GetBytes(post);
requestStream.Write(postBuffer, 0, postBuffer.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (StreamReader responseReader = new StreamReader(responseStream))
{
string json = responseReader.ReadToEnd();
shortUrl = Regex.Match(json, #"""id"": ?""(?<id>.+)""").Groups["id"].Value;
}
}
}
} catch (WebException webEx) {
System.Diagnostics.Debug.WriteLine (webEx.Message);
string responseText;
using(var reader = new StreamReader(webEx.Response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
}
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (ex.Message);
}
return shortUrl;
}
}
But I keep getting the "The remote server returned an error: (403) Forbidden." error.
I tried to debug and put a breakpoint on the 2nd using in the class..
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
It never goes inside that using and catches a WebException.
Can anyone give me an idea on what I'm doing wrong here?
Thank you for your time.
========================= UPDATE =========================
This is the value of the responseText from the WebException. I'm allowed to make 1,000,000 request per day. Why am I getting this error?
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
I figured it out!!
The key I created was for an Android device and it kept giving me that error.
So after realizing that it is IP issue, I created a SERVER KEY because no other key has IP option. I put the server key in my app and BOOM! it worked!
There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.
I read that as your API key is setup to be restricted by IP and your request is coming from an IP that is not registered to use that API key. Keep in mind that requests from the emulator will (most likely) have a different IP than the machine they are running on, because the Android emulator is a separate VM.
Either figure out the IP that the request is originating from and register it with your API key, or (if possible) switch the restriction to be per-Referer and handle that in your code.
Related
I have been searching everywhere on the Internet for Google Translate API usage but I wasn't able find descent tutorial or explanation. So, here is what I have done:
In my Google API Console I have generated a key under Public API access with my SHA1 Fingerprint using this answer. Here is how my API console looks like:
In Android studio I build and send my request using OkHttp library with this code:
OkHttpClient client = new OkHttpClient();
String apiKey = "My API key";
String apiLangSource = "en";
String apiLangTarget = "de";
String apiWord = "Hello";
String googleApiUrl = "https://www.googleapis.com/language/translate/v2?key=" + apiKey + "&source=" + apiLangSource + "&target=" + apiLangTarget + "&q=" + apiWord;
Request request = new Request.Builder().url(googleApiUrl).build();
Log.d(TAG, "API STRING" + googleApiUrl);
Call call = client.newCall(request);
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.d(TAG , "HTTP CALL FAIL");
}
#Override
public void onResponse(Response response) throws IOException {
Log.d(TAG , response.body().string());
}
});
It runs fine but on response I get:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
What is the problem here? Is my API set up correctly? Am I making the call correctly (I've seen some libraries but with guide)? Is this reasonable way of using this library? What exacty does this mean?
"There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
I think there are some demo calls available for free and this isn't the problem here.
Problem is when setting up your API key restriction for android app, you specified the package name and SHA-1 certificate fingerprint. Therefore your API key will only accept request from your app with package name and SHA-1 certificate fingerprint specified.
So how google know that request's sent FROM YOUR ANDROID APP? You MUST add your app's package name and SHA-1 in the header of each request with following keys:
Key: "X-Android-Package", value: your app package name
Key: "X-Android-Cert", value: SHA-1 certificate of your apk
FIRST, get your app SHA signature (you will need Guava library):
/**
* Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
*
* #param packageName Identifies the APK whose signature should be extracted.
* #return a lowercase, hex-encoded
*/
public static String getSignature(#NonNull PackageManager pm, #NonNull String packageName) {
try {
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (packageInfo == null
|| packageInfo.signatures == null
|| packageInfo.signatures.length == 0
|| packageInfo.signatures[0] == null) {
return null;
}
return signatureDigest(packageInfo.signatures[0]);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
private static String signatureDigest(Signature sig) {
byte[] signature = sig.toByteArray();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(signature);
return BaseEncoding.base16().lowerCase().encode(digest);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
Then, add package name and SHA certificate signature to request header:
java.net.URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// add package name to request header
String packageName = mActivity.getPackageName();
connection.setRequestProperty("X-Android-Package", packageName);
// add SHA certificate to request header
String sig = getSignature(mActivity.getPackageManager(), packageName);
connection.setRequestProperty("X-Android-Cert", sig);
connection.setRequestMethod("POST");
// ADD YOUR REQUEST BODY HERE
// ....................
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
}
Hope this help! :)
I want to use Google Translate API (v2) in my android application.
What I did:
created project in Google Developers Console
set up billing for this project
generated 2 public api access keys for android applications:
a. First one that accepts request from any application
b. Second one that accepts requests from my application only
I tried to translate text from the application via
https://www.googleapis.com/language/translate/v2?key=MY-KEY&target=de&q=Hello%20world
It works fine with the key from 3a) but does not work with the key from 3b). For 3b) server sends
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "ipRefererBlocked",
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."
}
}
I guess this is because google server does not receive any info about my application with this request, so it cannot acquire key 3b). If so, how to send this request correctly? Or, alternatively, what I did wrong somewhere else?
If so, how to send this request correctly?
When setting up your API key restriction for android app, you specified the package name and SHA-1 certificate fingerprint. So when you send an request to Google, you MUST add these information in the header of each request.
HOW?
As answered here, you need to get your package name and SHA certificate from your code, and then adding to request header.
Get SHA certificate:
/**
* Gets the SHA1 signature, hex encoded for inclusion with Google Cloud Platform API requests
*
* #param packageName Identifies the APK whose signature should be extracted.
* #return a lowercase, hex-encoded
*/
public static String getSignature(#NonNull PackageManager pm, #NonNull String packageName) {
try {
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
if (packageInfo == null
|| packageInfo.signatures == null
|| packageInfo.signatures.length == 0
|| packageInfo.signatures[0] == null) {
return null;
}
return signatureDigest(packageInfo.signatures[0]);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
private static String signatureDigest(Signature sig) {
byte[] signature = sig.toByteArray();
try {
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] digest = md.digest(signature);
return BaseEncoding.base16().lowerCase().encode(digest);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
Adding to request header:
java.net.URL url = new URL(REQUEST_URL);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestProperty("Accept", "application/json");
// add package name to request header
String packageName = mActivity.getPackageName();
connection.setRequestProperty("X-Android-Package", packageName);
// add SHA certificate to request header
String sig = getSignature(mActivity.getPackageManager(), packageName);
connection.setRequestProperty("X-Android-Cert", sig);
connection.setRequestMethod("POST");
// ADD YOUR REQUEST BODY HERE
// ....................
} catch (Exception e) {
e.printStackTrace();
} finally {
connection.disconnect();
}
You can see full answer here.
Enjoy coding :)
I am trying to create a image upload module Using Imgur API
I have just got Client ID and Client Secret after registration. When it comes to the implementation and testing, it fails and gives the following response in the logcat
The Logcat response
{"data":{"error":"We're really sorry, but
anonymous uploading in your country has
been disabled. Please <a href=\"\/register\">register
for an account<\/a> and try uploading again.","request":"\/3\/upload.json","method":"POST"}
,"success":false,"status":400}
The below is my code
public String uploadToImgur(File uploadFile) {
DefaultHttpClient defaulthttpclient;
HttpPost httppost;
MultipartEntity multipartentity;
String path = uploadFile.getAbsolutePath().toString();
String s;
defaulthttpclient = new DefaultHttpClient();
String targetURL = "https://api.imgur.com/3/upload.json";
String apikey = "client_secret";
httppost = new HttpPost(targetURL);
httppost.setHeader("User-Agent", USER_AGENT);
httppost.addHeader("Authorization", "Client-ID {client)_id}");
multipartentity = new MultipartEntity();
s = path.substring(1 + path.lastIndexOf("."));
if (s.lastIndexOf("jpg") >= 0)
{
s = "jpeg";
}
try
{
multipartentity.addPart("image", new FileBody(new File(path), (new StringBuilder("image/")).append(s).toString()));
multipartentity.addPart("key", new StringBody(apikey));
httppost.setEntity(multipartentity);
String s1 = EntityUtils.toString(defaulthttpclient.execute(httppost).getEntity());
Log.d("outpur" , s1);
if (s1.lastIndexOf("<original>") >= 0 && s1.indexOf("</original>") >= 0)
{
return (new StringBuilder("[img]")).append(s1.substring(10 + s1.lastIndexOf("<original>"), s1.indexOf("</original>"))).append("[/img]").toString();
}
}
catch (Exception exception)
{
return "ERRor";
}
return "Error";
}
Would you please tell me what is the better way to enhance the upload module ?
Registration and sending client id is not good enough for non anonymous uploads. The documentation tells you to use oAuth and get a token that needs to be passed for such requests.
Authentication
The API requires each client to use OAuth 2 authentication. This means you'll have to register your application, and generate an access_code if you'd like to log in as a user.
For public read-only and anonymous resources, such as getting image info, looking up user comments, etc. all you need to do is send an authorization header with your client_id in your requests. This also works if you'd like to upload images anonymously (without the image being tied to an account), or if you'd like to create an anonymous album. This lets us know which application is accessing the API.
Authorization: Client-ID YOUR_CLIENT_ID
For accessing a user's account, please visit the OAuth2 section of the docs
I am using google books API KEY for android to load book data via my android application. But I am getting error listed below.
However,
- The query works if I delete certificates from my API CONSOLE (e.g. make API KEY acceptable for all Applications). Though my {SHA1};{package name} information that I put is correct.
- This works if I use API KEY for browser instead.
Hence, what I can understand, I can't send KEY as a part of url in httpclient method. May be I need to send via header or something. But I can't find how.
Anybody can help please?
CODE:
String link = "https://www.googleapis.com/books/v1/volumes?key=MY_KEY&q="+query+"&projection=full&langRestrict=en&maxResults=1";
HttpGet get = new HttpGet(link);
HttpParams httpParameters = new BasicHttpParams();
int timeoutConnection = 10000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutConnection);
HttpClient httpclient = new DefaultHttpClient(httpParameters);
HttpResponse response = httpclient.execute(get);
HttpEntity entity = response.getEntity();
Query:
https://www.googleapis.com/books/v1/volumes?key=MY_API_KEY&q=intitle:'The+Old+Man+And+The+Sea'+inauthor:'Ernest+Hemingway'&projection=full&langRestrict=en&maxResults=1
Result:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured"
}
],
"code": 403,
"message": "Access Not Configured"
}
}
For whom it may concern ... I send my API key in header, and it is now working.. I am not sure whether this is the proper way to it though ...
String link = "https://www.googleapis.com/books/v1/volumes?q="+params;
InputStream is = null;
try
{
int timeoutConnection = 10000;
URL url = new URL(link);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(timeoutConnection);
con.setReadTimeout(timeoutConnection);
con.setRequestProperty("key", "API_KEY");
if(con.getResponseCode() != HttpURLConnection.HTTP_OK){
publishProgress("Error conneting.");
}
is=con.getInputStream();
}
Supplying the key in the header is the same as not supplying a key at all. Check your developer api console and you will see no successful queries with that api key. So in short the API key in header does not solve the problem. If you don't want to play by google's rules just do the query without the key at all.
You can achieve the same result of the accepted answer using HttpGet:
String API_KEY = "..."; // Google Books API Public key
String ISBN = "...";
String bookSearchString = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + ISBN;
HttpClient bookClient = new DefaultHttpClient();
try
{
//get the data
HttpGet bookGet = new HttpGet(bookSearchURL);
bookGet.addHeader("key", API_KEY);
HttpResponse bookResponse = bookClient.execute(bookGet);
StatusLine bookSearchStatus = bookResponse.getStatusLine();
if (bookSearchStatus.getStatusCode() == 200)
{
//we have a result
HttpEntity bookEntity = bookResponse.getEntity();
...
}
} catch (Exception e)
{
e.printStackTrace();
}
Note that using Google API key without restrictions is insecure way to do!
Obviously if you’re being charged for access to the API data then you don’t want someone to decompile your APK, find your API key, and then start using it in their own apps.
How to hide your API Key in Android?
But It's not enough. You can store your API key somewhere, so someone can find it too.
To secure Google cloud API key for your android app, you must restrict it to use from your app only. See here for more.
After restrict key, you must include your android app package name and SHA-1 certificate fingerprint in the header of each request you are sending to Google. How to do?
That's all you need ! :D
Running the code below I get "error" : "unauthorized_client". Need help pinpoint what I have done wrong.
I Want to use this in an Android app to enable Google Talk (xmpp is there already XABBER fork)
Reading much about how to do this and now come the Google Api Console setup.
I have chosen
- Client ID for installed applications
- Installed application type = Other
- Enabled only the Google Play Android Developer API (green switch)
I get the authentication token from oauth2:https://www.googleapis.com/auth/googletalk. (user approval screen)
What bugs me I dont enter the SHA1 fingerprint or package name for "Other" so maybe that's the problem
code:
HttpClient client1 = new DefaultHttpClient();
HttpPost request1 = new HttpPost("https://accounts.google.com/o/oauth2/token" );
request1.setHeader("Content-type", "application/x-www-form-urlencoded");
//Please make this custom with you're credentials
String requestBody1 =
"code="+authToken+
"&client_id=749825062016ia.apps.googleusercontent.com"+
"&client_secret=jQ1nUrAYUIBUf6hN5pwPE" +
"&redirect_uri=urn:ietf:wg:oauth:2.0:oob" +
"&grant_type=authorization_code";
try {
request1.setEntity(new StringEntity(requestBody1));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
/* Checking response */
try {
HttpResponse response = client1.execute(request1);
String results = "ERROR";
results = EntityUtils.toString(response.getEntity());
LogManager.i("STACK", "Response::" + results);
} catch (IOException e) {
e.printStackTrace();
}
I think you should have registered your application with type 'Android'. Then you will be asked to provide information (such as package name and certificate) that will allow the Android platform to recognize your application.