Currently working on a JIRA addon using the ACE framework. Executing a request using the integrated httpClient.
When I make a request such as this
https://instance.atlassian.net/rest/api/3/search
it works fine using the header Authorization: JWT <token> but when I run the same request with a query parameter like this
https://instance.atlassian.net/rest/api/3/search?maxResults=1
the request fails with a 401. I have confirmed that the JWT is not expired due to reverting the query parameters and seeing success again.
My atlassian-connect.json has scope READ as requested by the endpoint.
Any suggestions?
I was surprised that the rest call "rest/api/2/search?maxResults=1" worked. But it did when I was logged into my instance.
If I try that as JQL in Issue Search (maxResults=1), I get an invalid or unauthorized error message.
My instance is on premise (API V2). Yours appears to be in the cloud (V3). So it may be that the REST search works more like the Issue Search in V3 and is therefore returning the 401
It's a guess that should be easy to test... replace your maxResults=1 with some actual JQL or a filter ID and see if your results change
Since you're using ACE and utilizing httpClient, you might want to try the checkValidToken() route instead. The snippet below worked for me.
app.get('/mySearch', addon.checkValidToken(), function(req, res) {
var httpClient = addon.httpClient(req);
httpClient.get({
url: '/rest/api/3/search?maxResults=1',
headers: {
'X-Atlassian-Token': 'nocheck',
'Content-Type': 'application/json'
}
},
function (err, httpResponse, body) {
if (err) {
return console.error('Search failed:', err);
}
console.log('Search successful:', body);
});
});
Related
I'm trying to build a gRPC client for Google's Firestore API in Elixir.
Before starting to write some code , I thought that it would be wise to first start with BloomRPC in order to debug the issue.
As base url, I'm using https://firestore.googleapis.com where I pinned the rot certificate.
As auth I'm using an access_token obtained using oauth with the following 2 scopes: "https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/datastore"
being passed as a Authorization header:
{
"Authorization": "Bearer 29ya.a0AfH6SMBDYZPsVgQv0PMqyGRXypc3DfWF_2jbvAJKMquTaryCvxEB7X1Rbprfk1Ebrwid2bXbcR3Aw-d1Tytlo_lThkyqRDRIbnSz5-nQ3xWklkmjyFMAuQtFCoz01hk3vbgBwd2gdbFNNWiOU_8NqPC_vElyz2-cQ34"
}
And I get back:
{
"error": "3 INVALID_ARGUMENT: Missing required project ID."
}
So clearly I should be passing the project ID somehow but I can't find it anywhere in the docs. Anybody any clues?
I just figured out what I was doing wrong.
Basically the Bearer token I was using is correct (obtained via the OAuth Playground).
The trick was to specify the PROJECT_ID in the parent parameter of the request:
{
"parent": "projects/[project-id]/databases/(default)/documents",
"page_size": 10
}
I should have just read the docs properly :)
I cannot access the error (response) status code if an axios request has failed in my Vue.js app. I cannot figure out why the response is undefined in both '.catch' and 'axios.interceptors.response'. I followed this instruction that demonstrates that 'error.response' can be easily accessed with a code like this:
axios.interceptors.response.use(
(response) => {
console.log(response);
return response;
},
(error) => {
handleApiFail(error.response);
});
If I add this code to 'main.js' in my app, 'handleApiFail' is called when a request fails, but error.response is undefined in the second lambda and the first lambda is not called. If a request succeeded the 'response' in the first lambda is defined and has the status code.
EDIT1: this is not an option because my OPTIONS requests do not require authorization. Also there are various posts describing the same situation.
The lack of
access-control-allow-origin: *
header in the response caused the browser to block my request.
Adding the header makes axios work fine.
I have code like this:
axios.interceptors.response.use(null, (error) => {
.........
return Promise.reject();
});
Then, I found I miss to return my "error" in promise reject, correct like this:
return Promise.reject(error);
This is an idiosyncrasy of axios. A quick solution to this is to serialize the response:
JSON.stringify(error)
Please refer to this GitHub issue for more info: https://github.com/axios/axios/issues/960
As someone pointed out there, you can check the error status code in the action and run some other commit depending on it.
I'm trying to create OpenTok session by Rest services with JWT object as suggested. I tried to generate session with Fiddler.
Here is my fiddler request (JWT string has been changed with *** partially for security reasons)
POST https: //api.opentok.com/session/create HTTP/1.1
Host: api.opentok.com
X-OPENTOK-AUTH: json_web_token
Accept: application/json
Content-Length: 172
eyJ0eXAiOiJKV1QiL******iOiJIUzI1NiJ9.eyJpc3MiOjQ1NzM******OiJkZW5l******XQiOjE0ODI3OTIzO***SOMESIGNEDKEYHERE***.izvhwYcgwkGCyNjV*****2HRqiyBIYi9M
I got 403 {"code":-1,"message":"Invalid token format"} error probably means my JWT object is not correct. I tried creating it using http://jwt.io (as opentok suggests) and other sites and all seems correct and very similar to the one on tokbox (opentok) site.
I need an explanation to fix it and create a session.
May it be because I am using opentok trial?
JWT creation Parameters
I had the same problem. I resolved the error by setting the correct key-value pairs for the payload part.
Example of my payload is as follows in C#:
var payload = new Dictionary<string, object>()
{
{ "iss", "45728332" },
{ "ist", "project" },
{ "iat", ToUnixTime(issued) },
{ "exp", ToUnixTime(expire) }
};
The value of the "ist" should be set to "project", not the actual name of your project.
Update: Looking at your screenshot, I can say you have not set the secret key (here, it's your ApiKeySecret from TokBox account > project) at the very bottom right.
OK I have found the answer at last,
Your Opentok API Secret key should not be used directly as Sign parameter. In java as shown below, it should be encoded first.
Base64.encodeToString("db4******b51a4032a83*******5d19a*****e01".getBytes(),0)
I haven't tried it on http://jwt.io and fiddler but it seems it will work on it too. Thanks. Full code is below;
payload = Jwts.builder()
.setIssuedAt(currentTime)
.setIssuer("YOUR_OPENTOK_KEY")
.setExpiration(fiveMinutesAdded)
.claim("ist", "project")
.setHeaderParam("typ","JWT")
.signWith(SignatureAlgorithm.HS256, Base64.encodeToString("YOUR_OPENTOK_SECRET".getBytes(),0))
.compact();
return payload;
I'm developing an Angular2 application. It seems when my access-token expires the 401 HTTP Status code gets changed to a value of 0 in the Response object. I'm receiving 401 Unauthorized yet the ERROR Response object has a status of 0. This is preventing me from trapping a 401 error and attempting to refresh the token. What's causing the 401 HTTP status code to be changed into HTTP status code of 0?
Here's screenshot from Firefox's console:
Here's my code:
get(url: string, options?: RequestOptionsArgs): Observable<any>
{
//console.log('GET REQUEST...', url);
return super.get(url, options)
.catch((err: Response): any =>
{
console.log('************* ERROR Response', err);
if (err.status === 400 || err.status === 422)
{
return Observable.throw(err);
}
//NOT AUTHENTICATED
else if (err.status === 401)
{
this.authConfig.DeleteToken();
return Observable.throw(err);
}
else
{
// this.errorService.notifyError(err);
// return Observable.empty();
return Observable.throw(err);
}
})
// .retryWhen(error => error.delay(500))
// .timeout(2000, new Error('delay exceeded'))
.finally(() =>
{
//console.log('After the request...');
});
}
This code resides in a custom http service that extends Angular2's HTTP so I can intercept errors in a single location.
In Google Chrome, I get this error message:
XMLHttpRequest cannot load https://api.cloudcms.com/repositories/XXXXXXXXXXXXXXXX/branches/XXXXXXXXXXXXXXXX/nodesXXXXXXXXXXXXXXXX. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://screwtopmedia.local.solutiaconsulting.com' is therefore not allowed access. The response had HTTP status code 401.
This is confusing because I am including 'Access-Control-Allow-Origin' header in request.
Here's a picture of results received in Google Chrome:
I've tried accessing 'WWW-Authenticate' Response Header as a means to trap for 401. However, the following code returns a NULL:
err.headers.get("WWW-Authenticate")
It's puzzling that I'm getting a CORS issue because I'm not getting any CORS errors when a valid access token is provided.
How do I trap for 401 HTTP status code? Why is 401 HTTP status code being changed to 0?
Thanks for your help.
The issue is related to CORS requests, see this github issue
No 'Access-Control-Allow-Origin' header is present on the requested
resource
means that 'Access-Control-Allow-Origin' is required in the response headers.
Angular is not getting any status codes, that's why it gives you a 0 which is caused by browser not allowing the xml parser to parse the response due to invalid headers.
You need to append correct CORS headers to your error response as well as success.
If cloudcms.com do to not set the Access-Control-Allow-Origin in 401 response, then nothing much you can do. You properly have to open support ticket with them to confirm if that is normal behavior.
javascript in browsers(FF, Chrome & Safari) I tested won't receive any info if CORS error occur, other than status 0. Angular2 has no control of it.
I created a simple test and get the same result as yours:
geturl() {
console.log('geturl() clicked');
let headers = new Headers({ 'Content-Type': 'application/xhtml+xml' });
let options = new RequestOptions({ 'headers': headers });
this.http.get(this.url)
.catch((error): any => {
console.log('************* ERROR Response', error);
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Web Server error';
return Observable.throw(error);
})
.subscribe(
(i: Response) => { console.log(i); },
(e: any) => { console.log(e); }
);
}
After much googling, I found the following(https://github.com/angular/angular.js/issues/3336):
lucassp commented on Aug 19, 2013
I found the issue for a while now but I forgot post here a reply. EVERY response, even Error 500, must have the CORS headers attached. If the server doesn't attach the CORS headers to the Error 500 response then the XHR Object won't parse it, thus the XHR Object won't have any response body, status, or any other response data inside.
Result from Firefox network monitor seems supporting the above reason.
Javascript request will receive empty response.
Plain url request(copy&paste the link in the address bar) will get response body
Javascript use XHRHttpRequest for http communication.
When a XHR reply arrive, the browser will process the header, that's why you will see those 401 network messages. However, if the XHR reply is from a different host then the javascript AND the response header contain no CORS header(eg Access-Control-Allow-Origin: *), the browser will not pass any info back to the XHR layer. As a result, the reply body will be completely empty with no status(0).
I tested with FF 48.0.1, Chrome 52.0.2743.116 and Safari 9.1.2, and they all have the same behavior.
Use browser network monitor to check response header for those 401 Unauthorized entries, it is very likely that there is no Access-Control-Allow-Origin header and causing the issue you are facing. This can be a bug or by design on the service provider side.
Access-Control-Allow-Origin is a response only http header. For more information of https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#The_HTTP_response_headers
I work for Cloud CMS. I can confirm that we properly set CORS headers on API calls. However, for 401 responses the headers are not getting set properly. This has been resolved and the fix will be available on the public API at the end of this week.
BTW if you use our javascript driver https://github.com/gitana/gitana-javascript-driver instead of writing to the API directly then the re-auth flow is handled automatically and you do not need to trap 401 errors at all.
Stumbled upon this item:
What happens in my case was that:
I was requesting REST from different domain
The resource returned 401, but there was no "Access-Control-Allow-Origin" set in the error response.
Chrome (or your browser) received 401 and showed in network tab (See below count : 401), but never passed to Angular
since there was no CORS allowed (missing "Access-Control-Allow-Origin" header) - Chrome could not pass this response into Angular. This way I could see 401 in the Chrome but not in Angular.
Solution was simple (extends on TimothyBrake's answer) - to add the missing header into the error response. In Spring boot I put: response.addHeader("Access-Control-Allow-Origin", "*"); and I was sorted out.
#Component
public class JwtUnauthorizedResponseAuthenticationEntryPoint
implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"You would need to provide the Jwt Token to Access This resource");
}
}
PS: Make sure the bean is provided into HttpSecurity config in your WebSecurityConfigurerAdapter. Refer to: https://www.baeldung.com/spring-security-basic-authentication if in doubt.
Hope this helps.
According to W3C, if the status attribute is set to 0, it means that:
The state is UNSENT or OPENED.
or
The error flag is set.
I think that this isn't an Angular2 issue, it seems like your request has a problem.
I had the same issue and was due to the server not sending the correct response (even though the console log stated a 401 the Angular error had status 0). My server was Tomcat with Java application using Spring MVC and Spring Security.
It is now working using folowing setup:
SecurityConfig.java
...
protected void configure(HttpSecurity http) throws Exception {
....
http.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint);
// allow CORS option calls
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
...
SomeAuthenticationEntryPoint.java
#Component
public class SomeAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
HttpStatus responseStatus = HttpStatus.UNAUTHORIZED;
response.sendError(responseStatus.value(), responseStatus.getReasonPhrase());
}
}
web.xml
<error-page>
<error-code>403</error-code>
<location>/errors/unauthorised</location>
</error-page>
<error-page>
<error-code>401</error-code>
<location>/errors/unauthorised</location>
</error-page>
Controller to handle the /errors/... previously defined
#RestController
#RequestMapping("/errors")
public class SecurityExceptionController {
#RequestMapping("forbidden")
public void resourceNotFound() throws Exception {
// Intentionally empty
}
#RequestMapping("unauthorised")
public void unAuthorised() throws Exception {
// Intentionally empty
}
}
}
You should use a 3rd party http protocol monitor (like CharlesProxy) rather than Chrome dev tools to confirm which headers are actually being sent to the API service and if it is returning a 401.
I currently playing around with the Facebook JavaScript SDK and the Scores API ( https://developers.facebook.com/docs/score/ ). I wrote a small application to save (post) scores and now I want to delete scores. Posting (saving) them works fine.
My code looks like this:
var deleteHighScoreUrl = 'https://graph.facebook.com/'+facebook.user.id+'/scores?access_token='+facebook.application.id+'|'+facebook.application.secret;
jQuery.ajax(
{
type: 'DELETE',
async: false,
url: deleteHighScoreUrl,
success: function(data, textStatus, jqXHR)
{
console.log('Score deleted.');
}
});
The "facebook" variable is an object that holds my application data. For HTTP POST it works fine but for HTTP DELETE I get the response "NetworkError: 400 Bad Request" in Firebug (with Firefox 10). I saw that Firefox first sends an HTTP OPTIONS (to see if it is allowed to use HTTP DELETE) which leads to this error so I tried the same thing with Google Chrome. Google Chrome sends a real HTTP DELETE which then returns:
"XMLHttpRequest cannot load
https://graph.facebook.com/USER_ID/scores?access_token=APP_ID|APP_SECRET.
Origin MY_DOMAIN is not allowed by Access-Control-Allow-Origin".
I think that this is a classical cross domain issue but how to solve it? I've added my domain to my facebook application (at https://developers.facebook.com/apps) and Facebook has a paragraph which is called "Delete scores for a user". So it must be possible to delete the scores (somehow)?
Because of Cross-Site-Scripting (XSS) a HTTP DELETE is not possible. But you can send a HTTP POST request with the query parameter ?method=delete, which then deletes the score.
Code Sample:
Facebook.prototype.deleteUsersHighScore = function()
{
var deleteHighScoreUrl = 'https://graph.facebook.com/'+this.user.id+'/scores?access_token='+this.application.id+'|'+this.application.secret+'&method=delete';
jQuery.ajax(
{
type: 'POST',
async: false,
url: deleteHighScoreUrl,
success: function(data, textStatus, jqXHR)
{
console.log('Score deleted.');
}
});
}
This is the Cross Domain security issue.
The fact that your error contains the message "Origin MY_DOMAIN" would tell me that somewhere in your code you have copied one of Facebook's examples but not changed the value for MY_DOMAIN to the correct domain you are using.
I would check all of your code for the value "MY_DOMAIN".
Please ignore this advice if you have changed the value to hide your actual domain in your question.