I am trying to get a GitHub oauth access token. Redirecting the user to
https://github.com/login/oauth/authorize works fine and a get the code.
However, when I do the POST request from the server to https://github.com/login/oauth/acces_token,
the server responds with
403: Forbidden / Cookies must be enabled to use GitHub.
Am I getting something wrong here? It's an API! What is the role of cookies here? How can I fix the error?
My Code is (using OkHttp)
String code= ...;
HttpUrl url = new HttpUrl.Builder()
.scheme("https").host("github.com")
.addPathSegments("login/oauth/acces_token")
.build();
StringBuilder formEncoded = new StringBuilder();
formEncoded.append("client_id=").append(URLEncoder.encode(..., "UTF-8"));
formEncoded.append("&client_secret=").append(URLEncoder.encode(..., "UTF-8"));
formEncoded.append("&code=").append(URLEncoder.encode(code, "UTF-8"));
Response resp = client.newCall(
new Request.Builder().url(url)
.post(RequestBody.create(
MediaType.parse("application/x-www-form-urlencoded"),
formEncoded.toString()))
.addHeader("Accept", "application/json").build())
.execute();
if (resp.code() != HttpServletResponse.SC_OK) {
log.error("Error while getting token: {}: {} / {}",
resp.code(), resp.message(), resp.body().string());
throw new RuntimeException("Error while getting access token");
}
Found the error: Typo in the URL. I had acces_token, should be access_token. Now it works like a charm.
Related
Basically i'm new to groovy, and i'm trying to use it to add a device to "netbox" using API, i tried some GET requests that needed authentication and they worked fine, but i couldn't make any POST request work, i'm always getting 403 no matter what method i try to authenticate Basic using creds or using API Token.
Here's the code i wrote for the POST request :
def url = "http://192.168.12.89:8000/api/dcim/devices"
def connection = url.toURL().openConnection()
def message = '{"name":"R4","device_type":"1","device_role":"1","site":"1"}'
connection.setRequestMethod("POST")
connection.setDoOutput(true)
connection.setDoInput(true)
connection.addRequestProperty("Accept", "application/json;charset=UTF-8")
connection.addRequestProperty("Content-Type", "application/json")
//def auth = "admin:admin".bytes.encodeBase64()
//connection.setRequestProperty("Authorization", "Basic ${auth}")
connection.setRequestProperty("Authorization", "Token 63091d94b00d40e9e0a4e1286e181c09deca6e89")
connection.getOutputStream().write(message.getBytes("UTF-8"))
def responseCode = connection.getResponseCode()
InputStream response = null
println "${responseCode}"
if (responseCode != 200) {
response = connection.getErrorStream()
} else {
response = connection.getInputStream()
}
def responseBody = response?.text
response?.close()
println responseBody
My API key works fine with the get method and it has the write permissions included, also tried a python POST request works perfectly fine, so i guess the problem is in my groovy coding.
I hope i can get a bit of help cause i've been trying for two days :x
Thank you :x
I am trying to perform a get request using Groovy using the below code:
String url = "url of endpoint"
def responseXml = new XmlSlurper().parse(url)
If the endpoint returns status as 200 then everything works good but there is one case where we have to validate the error response like below and status returned is 400:
<errors>
<error>One of the following parameters is required: xyz, abc.</error>
<error>One of the following parameters is required: xyz, mno.</error>
</errors>
In this case parse method throws :
java.io.IOException: Server returned HTTP response code: 400 for URL: "actual endpoint throwing error"
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1900)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1498)
at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:646)
at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:150)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:831)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:796)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:142)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:644)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:205)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:271)
Can anyone pls suggest how to handle if server give error message by throwing 400 status code?
In the question since we are getting 400 status code for GET request. So in built XmlSlurper().parse(URI) method does not work as it throw io.Exception.
Groovy also support HTTP methods for api request and response and the below worked for me:
def getReponseBody(endpoint) {
URL url = new URL(endpoint)
HttpURLConnection get = (HttpURLConnection)url.openConnection()
get.setRequestMethod("GET")
def getRC = get.getResponseCode()
BufferedReader br = new BufferedReader(new InputStreamReader(get.getErrorStream()))
StringBuffer xmlObject = new StringBuffer()
def eachLine
while((eachLine = br.readLine()) !=null){
xmlObject.append(eachLine)
}
get.disconnect()
return new XmlSlurper().parseText(xmlObject.toString())
}
Getting the response text from the HttpURLConnection class rather than implicitly through XmlSlurper allows you much more flexibility in handling unsuccessful responses. Try something like this:
def connection = new URL('https://your.url/goes.here').openConnection()
def content = { ->
try {
connection.content as String
} catch (e) {
connection.responseMessage
}
}()
if (content) {
def responseXml = new XmlSlurper().parseText(content)
doStuffWithResponseXml(responseXml)
}
Even better would be to use an actual full-featured HTTP client, like the Spring Framework's HttpClient or RestTemplate classes.
You should check the return code and than obtain the error stream from http request instance in case of an error. The problem itself has nothing to do with JsonSlurper, as no instance of "input stream" is returned from http request instance if service returns not successfull return codes (400, 401, 500 etc.) POST example can be seen below:
http= new URL("yourUrl").openConnection() as HttpURLConnection
http.setRequestMethod('POST')
http.setDoOutput(true)
http.setRequestProperty("Content-Type", 'application/json')
http.setRequestProperty("Accept", 'application/json')
http.setRequestProperty("Authorization", "Bearer $yourTokenVariable")
http.outputStream.write(data.getBytes("UTF-8"))
http.connect()
if(http.getResponseCode() != 200 && http.getResponseCode() != 201){
throw new InvalidInputException("There was an error: " + http.getErrorStream().getText("UTF-8"))
} else {
//You can take input stream here
}
Here is the code snippet where I am trying to upload a document with some custom metadata using AWS S3 pre signed URL.
try (CloseableHttpClient httpClient = HttpClients.createSystem()) {
var tempFile = File.createTempFile(document.getName(), FilenameUtils.getExtension(document.getOriginalFilename()));
document.transferTo(tempFile);
var fileEntity = new FileEntity(tempFile);
var httpPut = new HttpPut(url);
// Here 403 httpPut.setHeader("x-amz-meta-title", "Test Title");
httpPut.setEntity(fileEntity);
var response = httpClient.execute(httpPut);
log.info("HTTP response code {}", response.getStatusLine().getStatusCode());
} catch (IOException e) {
log.error("Oops! Error", e);
}
Unfortunately setting a custom header as above throws 403. It works fine when I take out the header. Even works okay when you add an irrelevant metadata key say "abc" - Obviously not adding metadata, but returns 200 OK. The issue seems only when you specify "x-amz-meta-".
Any thoughts?
The metadata of a presigned url are set, when you create it. They are prefilled and can't be modified by the client.
The only thing you can do is set an expected value and optionally a condition. In the condition you can specify to reject the upload, if the expected meta-data value isn't supplied.
I'm trying to write a test to receive a JSON response from an API and I need to set a security token in the header for the API call. I've already verified that I am receiving a valid token from the get/token API. When I try to execute the HttpGet I am receiving a 401 status code.
Update: Does anyone have a complete list of authorization token types?
public void listAllDoctors() throws IOException {
String listAllDoctors = "/api/doctors/search";
HttpGet getDEV = new HttpGet(DEVBASE_ENDPOINT + listAllDoctors);
getDEV.setHeader(HttpHeaders.AUTHORIZATION, "token " + TOKEN);
getDEV.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
response = client.execute(getDEV);
int actualStatus = response.getStatusLine().getStatusCode();
assertEquals(actualStatus, 200);
}
I figured out that the API uses a custom header token authentication. So the line of code goes like this:
getDev.setHeader("token", "Token value goes here");
I am trying to connect to a URL from a desktop app, and I get the error indicated in the Title of my question, but when I tried to connect to the same URL from servlet, all works fine. When I load the URL from browser, all works fine. I am using the same code in the servlet. The code was in a library, when it didn't work, I pulled the code out to a class in the current project, yet it didn't work.
The URL https://graph.facebook.com/me.
The Code fragment.
public static String post(String urlSpec, String data) throws Exception {
URL url = new URL(urlSpec);
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(data);
writer.flush();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = "";
StringBuilder builder = new StringBuilder();
while((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
}
I'm a little bit confused here, is there something that is present is a servlet that is not a normal desktop app?
Thanks.
FULL STACK TRACE
Feb 8, 2011 9:54:14 AM com.trinisoftinc.jiraffe.objects.FacebookAlbum create
SEVERE: null
java.io.IOException: Server returned HTTP response code: 400 for URL: https://graph.facebook.com/me
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1313)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at com.jiraffe.helpers.Util.post(Util.java:49)
at com.trinisoftinc.jiraffe.objects.FacebookAlbum.create(FacebookAlbum.java:211)
at com.trinisoftinc.jiraffe.objects.FacebookAlbum.main(FacebookAlbum.java:261)
EDIT: You need to find the exact error message that facebook is sending in the response
You can modify your code to get the message from the error stream like so:
HttpURLConnection httpConn = (HttpURLConnection)connection;
InputStream is;
if (httpConn.getResponseCode() >= 400) {
is = httpConn.getErrorStream();
} else {
is = httpConn.getInputStream();
}
Take a look at how you are passing the user context
Here's some information that could help you out:
Look at the error message behind the 400 response code:
"Facebook Platform" "invalid_request" "An active access token must be used to query information about the current user*
You'll find the solution here
HTTP/1.1 400 Bad Request
...
WWW-Authenticate: OAuth "Facebook Platform" "invalid_request" "An active access token must be used to query information about the current user."
...
I finally found the problem. Of course it's my code. One part of the code I didn't post is the value of data. data must contain only name and description but I am passing more than name and description.