I am trying to access the Drive Api from a JavaFX Desktop app. After I received the initial authentication (aka code), I want to get the token to be able to work with the api. The config is set up as a native application in the dev console.
When I attempt to fetch the token I get various http-errors (400, 401, 404, 405, 406, 411). I guess something is wrong with the encoding and/or the way I send the request to the server.
Here the code:
public void sendOAuth2TokenRequest(String initialOAuth2) {
final String charset = "UTF-8";
try {
String url = "https://www.googleapis.com/oauth2/v3/token";
HttpsURLConnection con = (HttpsURLConnection) new URL(url).openConnection();
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Accept-Charset", charset);
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
OutputStream output = con.getOutputStream();
output.write(getEncodedUrlParms().getBytes(charset));
output.close();
BufferedReader responseReader =
new BufferedReader(new InputStreamReader(con.getInputStream(), charset));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = responseReader.readLine()) != null) {
response.append(inputLine);
}
Log.i(TAG, "OAuth2Request " + inputLine);
responseReader.close();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "OAuth2Request Error: " + e.getMessage());
}
}
private String getEncodedUrlParms() throws UnsupportedEncodingException {
return "code=" + URLEncoder.encode(getInitialCode(), "UTF-8") +
"&client_id=" + URLEncoder.encode(DriveHelper.CLIENT_ID, "UTF-8") +
"&client_secret=" + URLEncoder.encode(DriveHelper.CLIENT_SECRET, "UTF-8") +
"&redirect_uri=" + URLEncoder.encode("urn:ietf:wg:oauth:2.0:oob", "UTF-8") +
"&grant_type=" + URLEncoder.encode("authorization_code", "UTF-8");
}
Please let me know what the mean here:
The client secret you obtained from the Developers Console (optional for clients registered as Android, iOS or Chrome applications).
Is the client_secret needed (mandatory) in native apps?
Related
I am creating a Java Rest api to create users on Google Duo admin. I am following the documentation https://duo.com/docs/adminapi and I have added auth and date/time header but still I am getting unauthorised error 401. Can anyone guide me what am I doing wrong I have read the doc and added all the mandatory headers.
public static void POSTRequest() throws IOException {
String userCredentials = "Username:Password";
String basicAuth = "Basic " + new String(Base64.getEncoder().encode(userCredentials.getBytes()));
String dateTime = OffsetDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME);
String POST_PARAMS = "{\n" + "\"userId\": 101,\r\n" +
" \"id\": 101,\r\n" +
" \"title\": \"Test Title\",\r\n" +
" \"body\": \"Test Body\"" + "\n}";
URL obj = new URL("https://api-e9770554.duosecurity.com");
HttpURLConnection postConnection = (HttpURLConnection) obj.openConnection();
postConnection.setRequestMethod("POST");
postConnection.setRequestProperty("Content-Type", "application/json");
postConnection.setRequestProperty("Authorization", basicAuth);
postConnection.setRequestProperty("Date", dateTime);
postConnection.setDoOutput(true);
OutputStream os = postConnection.getOutputStream();
os.write(POST_PARAMS.getBytes());
os.flush();
os.close();
int responseCode = postConnection.getResponseCode();
System.out.println("POST Response Code : " + responseCode);
System.out.println("POST Response Message : " + postConnection.getResponseMessage());
if (responseCode == HttpURLConnection.HTTP_CREATED) { //success
BufferedReader in = new BufferedReader(new InputStreamReader(
postConnection.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
System.out.println(response.toString());
} else {
System.out.println("POST NOT WORKED");
}
}
Error:
{
"code": 40101,
"message": "Missing request credentials",
"stat": "FAIL"
}
Response code: 401 (Unauthorized); Time: 2022ms; Content length: 73 bytes
I am trying to connect my android app to shutterstock api so that it can search for some images there. It uses https scheme + Basic Authentication header to allow users for all search requests. I implemented the functionality in a regular java project using HttpsURLConnection and was able to get correct JSON responses.
The java code looks like this:
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();//proxy);
String username = "62c01aa824222683004b", password = "dc4ad748a75e4e69ec853ad2435a62b700e66164";
String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes("UTF-8"));
System.out.println(encoded.equals("Nj0jMDFhZWE4ZmE4MjY4MzAwNGI6ZGM0YWQ3NDhhNzVlNGU2gWVjODUzYWQ0ZmEzYTYyYjc7MGU2NjE2NA==")); // prints true
urlConnection.setRequestProperty("Authorization", "Basic "+encoded);
When ported this into Android, it was throwing an IOException with 401 error code. As explained in many posts on SO (like the one here), I modified the code accordingly with an extra try-catch as below:
String username = "62c01aa824222683004b", password = "dc4ad748a75e4e69ec853ad2435a62b700e66164", encoded = "";
encoded = Base64.encodeToString((username+":"+password).getBytes("UTF-8"), Base64.URL_SAFE);
Log.e("test", "encoded strings match:" + encoded.equals("Nj0jMDFhZWE4ZmE4MjY4MzAwNGI6ZGM0YWQ3NDhhNzVlNGU2gWVjODUzYWQ0ZmEzYTYyYjc7MGU2NjE2NA==") + "\n" + encoded); // prints false but string is same!!
URL url = new URL(reqUrl);
connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Authorization", "Basic "+encoded);
try {
if (connection != null) {
connection.connect();
if (200 == connection.getResponseCode()) { // ---> throws IOException
BufferedReader br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
String output;
while ((output = br.readLine()) != null) {
Log.e("test", output);
response.append(output);
}
connection.disconnect();
return response.toString();
}
}
} catch (IOException e) {
try {
Log.e("test", e.getMessage()); // ---> prints "No authentication challenges found"
Log.e("test", connection.getResponseCode() + ":" + connection.getResponseMessage() + connection.getHeaderFields());
//---> prints 401:Unauthorized{null=[HTTP/1.1 401 Unauthorized], cache-control=[no-cache], Connection=[keep-alive], Content-Length=[38], Content-Type=[application/json; charset=utf8], Date=[Tue, 31 May 2016 14:11:28 GMT], Server=[nginx], X-Android-Received-Millis=[1464703888222], X-Android-Sent-Millis=[1464703887592], x-end-user-request-id=[f754ec7f-c344-431b-b641-360aabb70184], x-shutterstock-app-version=[apitwo-625], x-shutterstock-resource=[/v2/images/search]}
if (401 == connection.getResponseCode()) {
InputStream es = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(es));
String output;
while ((output = br.readLine()) != null) {
Log.e("test", output); // ---> prints {"message":"Invalid auth credentials"}
response.append(output);
}
connection.disconnect();
return response.toString();
} else {
Log.e("test","Could not connect! " + connection.getResponseCode() + ":" + connection.getResponseMessage() + ". " + connection.getRequestMethod());
}
}catch (Exception e1){e1.printStackTrace();}
}
I was unable to check the response headers in Firefox's Rest client because it does not send the request to server when I add the Authentication header.
So the questions here are:
Is this the right way to handle the 401 error in Android? Will I get the JSON response in the inner try-catch?
The java program uses exactly the same encoded string as in Android. How come the String.equals() returns "true" in java but "false" in android?
The error message from the server says "Invalid auth credentials". Does the encoded string differ between Android and Java for any reason? If yes, then point 2 makes sense.
I copied the encoded string from the java program into the Android variable and was able to authenticate successfully with shutterstock. So Indeed the encoded strings on Android and Java were different though in UTF-8 format. This also explains the "false" in Android and the "Invalid credentials" message from the server.
Just not sure why/how it differs when both the encoded strings are the same for the human eyes!
I am trying to send notification message for IOS through GCM from JAVA. That time i am getting one error with 400 status code Bad Request. Below i have mentioned my JAVA code...
String apiKey = "xxxxxxxxxxxxxxxxxxxx"; // Put here your API key
String GCM_Token = regid; // put the GCM Token you want to send to here
String notification = "{\"sound\":\"default\",\"badge\":\"2\",\"title\":\"default\",\"body\":\"Test Push!\"}"; // put the message you want to send here
String messageToSend = "{\"to\":\"" + GCM_Token + "\",\"notification\":" + notification + ",\"content_available\" : true}"; // Construct the message.
TRY{
URL url = new URL("https://android.googleapis.com/gcm/send");
System.out.println("Message"+messageToSend);
// Open connection
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//Set the headers
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestProperty("Authorization", "key=" + apiKey);
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.write(messageToSend.getBytes("UTF-8"));
//Send the request and close
wr.flush();
wr.close();
//Get the response
int responseCode = conn.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
System.out.println("Message : " + conn.getResponseMessage());
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//Print result
System.out.println(response.toString()); //this is a good place to check for errors using the codes in http://androidcommunitydocs.com/reference/com/google/android/gcm/server/Constants.html
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
please give me the suggestion.Thanks in advance.
I'm trying to set the OAuth Authorization header of a HttpsURLConnection object and below is the java code for that
String url1 = "/data/ServiceAccount?schema=1.0&form=json&byBillingAccountId={EQUALS,xyz#pqr.edu}";
String url = "https://secure.api.abc.net/data/ServiceAccount?schema=1.0&byBillingAccountId={EQUALS,xyz#pqr.edu}";
String header = OAuthClient.prepareURLWithOAuthSignature(url1);
HttpsURLConnection con = null;
try {
URL obj = new URL(url);
con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Authorization", "OAuth " + header);
System.out.println("Request properties = " + con.getRequestProperty("Authorization"));
int responseCode = con.getResponseCode();
System.out.println("Response Code = " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
con.disconnect();
//print result
System.out.println("Response = " + response.toString());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(con!=null) con.disconnect();
}
And below is the code for prepareURLWithOAuthSignature
public String prepareURLWithOAuthSignature(String url)
{
String signature = null;
setOAuthParameters();
setOAuthQParams();
try
{
httpURL = URLEncoder.encode(baseURL+url, "UTF-8");
signature = OAuthSignatureService.getSignature(httpURL, URLEncoder.encode(URLEncodedUtils.format(qparams, "UTF-8"), "UTF-8"), consumer_secret);
OAuthParameters.put("oauth_signature", signature);
} catch (Exception e) {
e.printStackTrace();
}
return getOAuthAuthorizationHeader();
}
public String getOAuthAuthorizationHeader()
{
String OAuthHeader = "oauth_consumer_key=\"" + OAuthParameters.get("oauth_consumer_key") + "\"" +
",oauth_signature_method=\"" + OAuthParameters.get("oauth_signature_method") + "\"" +
",oauth_timestamp=\"" + OAuthParameters.get("oauth_timestamp") + "\"" +
",oauth_nonce=\"" + OAuthParameters.get("oauth_nonce") + "\"" +
",oauth_version=\"" + OAuthParameters.get("oauth_version") + "\"" +
",oauth_signature=\"" + OAuthParameters.get("oauth_signature") + "\"";
byte[] authEncBytes = Base64.encodeBase64(OAuthHeader.getBytes());
String authStringEnc = new String(authEncBytes);
return authStringEnc;
}
The problem is that
1) while I'm printing the con.getRequestProperty("Authorization") I'm getting a null value which means the Authorization header is not set
2) The final response I'm getting from the server is 403
Any idea what's going wrong here?
I know this might not be an answer but looks like this issue was submitted as a bug to sun and here is the relevant part of the reply.
This behavior is intentional in order to prevent a security hole that
getRequestProperty() opened. setRequestProperty("Authorization")
should still work, you just won't be able to proof the results via
getRequestProperty().
For the original forum post, please see: http://www.coderanch.com/t/205485/sockets/java/setRequestProperty-authorization-JDK
I would not be able to advice why you're getting a 403 but try adding the "Content-Type" request header to your connection and see if it makes any difference. Until I added that header in my code, I was getting a 404 back from the Spring Security module.
I am trying to get content from the website Socialcast which needs authentication. (First I do a HTTP Post with Basic Authentication and then I try a HTTP GET).
I tried several codes, I receive this as "result":
emily#socialcast.com:demo
Base64 encoded auth string: ZW1pbHlAc29jaWFsY2FzdC5jb206ZGVtbw==
* BEGIN
You are being redirected.
END *
Here is the code for HTTP Basic Auth:
try {
String webPage = "http://demo.socialcast.com";
String name = "emily#socialcast.com";
String password = "demo";
String authString = name + ":" + password;
System.out.println("auth string: " + authString);
byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
String authStringEnc = new String(authEncBytes);
System.out.println("Base64 encoded auth string: " + authStringEnc);
URL url = new URL(webPage);
URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic " + authStringEnc);
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
int numCharsRead;
char[] charArray = new char[1024];
StringBuffer sb = new StringBuffer();
while ((numCharsRead = isr.read(charArray)) > 0) {
sb.append(charArray, 0, numCharsRead);
}
String result = sb.toString();
System.out.println("*** BEGIN ***");
System.out.println(result);
System.out.println("*** END ***");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
However, when I try to do a GET afterwards, it says unauthorized.
The credentials are emily#socialcast.com/demo - those are provided by Socialcast Dev at the moment, as I also cannot access my own Socialcast instance.
Is this code wrong? How can I do it properly? BTW, I am using HttpClient 4.x.
Are you sending the credentials in each request? I think this is needed, otherwise the server does not have any other information to prove that you still are authorized to view other pages...
I'm not sure why this question is tagged with apache-httpclient-4.x when your example code doesn't use it. In fact, if you do use httpclient then you can get it to handle authentication for you quite easily, see here for the excellent tutorial.