Handling 401 Unauthorised responses with visionmedia/superagent - javascript

Background
I'm using visionmedia/superagent to access my REST API. The API is currently available on a different domain and has CORS setup to allow cross domain requests from my client. To access the API securely I pass an Authorization header with an access token. The token has a short life and when it expires I can make a request for a new one using a refresh token. When an access token has expired the server will respond with a 401 error to let me know the request was Unauthorised.
Problem
I am trying to catch the 401 Unauthorised request with superagent, then handle the token refresh. The problem is superagent is not returning a standard response or error for the 401. I get a string response instead of an object.
Error Response
Error: Request has been terminated
Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.
at Request.crossDomainError (client.js:616)
at XMLHttpRequest.xhr.onreadystatechange (client.js:724)
Call
ajax.get(api.baseURL + '/some_request)
.accept('application/json')
.set('Content-Type', 'application/json')
.set('Authorization', 'Bearer ' + this.getAccessToken())
.send({...})
.then((sucess) => {
//handle success, update data
})
.catch((error) => {
//handle error, if 401 refresh the token and try again.
});
Additional Information
The server is successfully handling the CORS side of things, the initial OPTIONS request is returning successfully with a 200.
I have tried using the non ES6 .end((error, response) => {...} method to handle responses with the same result.
I'm using superagent version "3.4.0"
I have tried catching the error event, get the same error string.
.on('response', (error, response) => {
//manage error
})
.on('error', function(err) {
//manage error
})
My server 401 response has a json response body, and returns a Content-Type:application/json; charset=UTF-8 header
{
"name":"Unauthorized",
"message":"You are requesting with an invalid credential.",
"code":0,
"status":401,
"type":"yii\\web\\UnauthorizedHttpException"
}
Question
What do I need to do to get access to the error object for a 401 response? I want to be able to check the error.status to see if its a 401 so I can refresh the token?

Related

Get authorization token from headers into fetch reactj

I am using fetch in my react project to fetch data from an API which is authenticated using a token and my login end-point in the postman return the token in authorization header, you can see
and this's my login funtion in reactjs project
async login(dataLogin) {
const response = await fetch(`${API_URL}/login`, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: dataLogin
});
const data = await response
console.log(response.headers);
console.log(response.headers.Authorization);
console.log(response.headers.get('Authorization'));
return data;}
you can see that response.headers.authorization return undefined and
response.headers.get('Authorization') return null.
and you can see in my browsers' Network panel
please anyone know how to get the authorization token from the headers?
When you are trying to login using API, then you should receive data i.e. Authorization token or anything else in the response of call.
Check what is the response you're getting when you called an API, it should probably be like
response.data
First you need to check the same in Postman.
To access value of response header server must return header name in Access-Control-Expose-Headers header. Without it Authorization is inaccessible in browser.
response.headers.get('Authorization')
Edit:
Since you are getting null, consider that:
The Authorization header is usually, but not always, sent after the
user agent first attempts to request a protected resource without
credentials.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
Therefore, instead of using postman, in order to see the response header, use the browsers' Network panel.

Http status code 412 - Precondition failed

Getting 412 status code in response while trying to call restful service
While calling a restful service through ajax, I am passing authentication token in request header and a request body which is a json object. The response that I get from server is caught as 412 status code.
{"code":412,"status":"Precondition Failed","message":"User queryAll failed: Unexpected error parsing authentication token: 7d6f7d04-2b75-480d-8412-e6b9c173fb0e: Unable to convert authentication token to session: Unable to handle credentials from REST request body: [Authentication tag check failed. Message=ct5Rp34R2jgOlMUl29ElZg calculated=jwxpg_IzZKLrQACDM_D8pw]: [Unable to handle credentials from REST request body: [Authentication tag check failed. Message=ct5Rp34R2jgOlMUl29ElZg calculated=jwxpg_IzZKLrQACDM_D8pw]]: [7d6f7d04-2b75-480d-8412-e6b9c173fb0e: Unable to convert authentication token to session: Unable to handle credentials from REST request body: [Authentication tag check failed. Message=ct5Rp34R2jgOlMUl29ElZg calculated=jwxpg_IzZKLrQACDM_D8pw]: [Unable to handle credentials from REST request body: [Authentication tag check failed. Message=ct5Rp34R2jgOlMUl29ElZg calculated=jwxpg_IzZKLrQACDM_D8pw]]]","objectData":null}

axios interceptors response undefined

I'm trying to logout my user once they get a 401. I'm using axios to return data from the api
I was looking around and found the same axios.interceptors.response
axios.interceptors.response.use(
response => response,
error => {
const {status} = error.response;
if (status === 401 ) {
store.dispatch('snackBar', snackbarObj)
}
return Promise.reject(error);
}
)
It appears my error.response is undefined. I'm not sure what is wrong? any ideas?
You're not getting a response from the request you're doing with Axios since the browser received a 401 unauthorized response when doing the preflight OPTION request, resulting in a Network Error for the request you're trying to do.
This is related to how CORS works and how your backend handles OPTION requests. To understand how the backend server should handle preflight requests, it's important to understand what is the motivation behind introducing preflight requests.
The backend server should not check for authentication on OPTION requests, it should validate that the request is being made to an endpoint that accepts cross-domain requests and return a success code if it does.
Then, automatically, the browser will proceed with the initially intended request.
That way, the Axios interceptor will receive the 401 error code if the user is no longer authenticated.
Shameless self-promotion, I've published a simple Axios plugin called axios-middleware which helps abstract the use of Axios interceptors in bigger apps. It offers an example of middleware that automatically handles unauthenticated requests by trying to authenticate again before resending the request.
Response object will be undefined also if preflight OPTION request ended successfull, but response for next GET/POST doesn't contain Access-Control-Allow-Origin http-header.
In my case adding Access-Control-Allow-Origin header for nginx 401 response solves problem
For those who still struggling with this, use the following error handling for better control
if (error.response) {
// Request made and server responded
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
return Promise.reject(error);
it is not best practice but i solve it this way
axios.interceptors.response.use(
response => response,
error => {
if (typeof error.response === "undefined") {
// do somthing
}
return Promise.reject(error);
}
)

Best way to avoid HTTP 403 error when getting Set-Cookie header to set CSRF Cookie

I'm calling a REST API that has CSRF protection.
Everything works well. I'm getting the token and sending it back to the server.
However, when I do the very first request or when the CSRF Cookie is not set in the browser it always throws an HTTP 403 error.
This is because I didn't send CSRF token back given that this is the very first request in which the server sends the Set-Cookie header to set the CSRF Cookie.
What would be the best way to avoid this error the first time we send a request to a CSRF-protected API?
Should I check every time if the CSRF Cookie is set in the browser before sending any request?
You can do something like this. This is a dummy script.
checkIfAuthenticated()
.then( token => {
// user is authorized. use token
})
.catch( err => {
// oops. not authorized probably. authenticate user here.
});
// and your checkifAuthenticated:
function checkifAuthenticated() {
return new Promise((resovle, reject) => {
// perform a http request here to /api?checkauth
if(api_returned_401) {
reject('not authenticated');
} else {
resolve(tokenOrInfo);
}
});
}

5xx or 4xx error with “No 'Access-Control-Allow-Origin' header is present”

My browser is logging the following message in the devtools console:
No 'Access-Control-Allow-Origin' header is present on the requested resource.… The response had HTTP status code 503.
Background: I have two apps. One that is an Express Node application connected to a Mongo database. The other is a basic web application that makes POST requests to the Node application via the Fetch API to get data from Mongo.
Issue: Though I receive no CORS errors on my local machine, I am given the error below as soon as I deploy my basic web application to production. The web application that makes a POST request to the Node app and gives me this:
The POST request does seem to work and the data is saved into Mongo but this error is being marked as a "Critical Error" in Heroku and is quite annoying.
I realize that I could set the no-cors option in Fetch but I believe that it is required since I am making a request to a url that is different than the origin. Right?
Express Node App Code
In my app.js file I have set the correct headers to ensure that other applications can make requests from different origins
app.js
// Add headers so we can make API requests
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
routes/api/api.js
router.post('/users/:url/upload-csv/:csv_name', (req, res) => {
let csv_name = req.params.csv_name;
let csv_string = csv_name+req.body.csv_string;
User.findOne({url: req.params.url})
.then((user) => {
if (user.csv_files.length === 0) {
user.csv_files.push(csv_string);
} else {
let foundExistingCSV = false;
for (var i = 0; i < user.csv_files.length; i++) {
if (user.csv_files[i].includes(csv_name)) {
foundExistingCSV = true;
user.csv_files[i] = csv_string;
break;
}
}
if (!foundExistingCSV) user.csv_files.push(csv_string);
}
user.markModified('csv_files');
user.save();
res.status(204);
})
.catch((err) => {
console.log(err);
res.status(400);
});
});
Basic Web App Code
POST request I am making
utils.js
utils.exportToMongo = functions(table, name) {
var exportPlugin = table.getPlugin('exportFile');
var csv_string = exportPlugin.exportAsString('csv');
// Upload the CSV string and its name to Users DB
fetch(`${utils.fetchUserURL()}/upload-csv/${name}`, {
method: 'POST',
body: JSON.stringify({csv_string: csv_string}),
headers: new Headers({
'Content-Type': 'application/json',
Accept: 'application/json',
})
}).then((res) => {
return {};
}).catch((error) => {
console.log(error);
return {};
});
}
How can I remove the 503 error? Any insight would be greatly appreciated!
An HTTP 5xx error indicates some failure on the server side. Or it can even indicate the server just isn’t responding at all — e.g., a case might be, your backend tries to proxy a request to a server on another port, but the server is not even be up and listening on the expected port.
Similarly, a 4xx indicates some problem with the request prevented the server from handling it.
To confirm, you can try making the same request using curl, or Postman, or something, and see if you get a 2xx success response for the request, rather than a 5xx or 4xx.
Regardless, if you see a 5xx or 4xx error on the client side, some message should get logged on the server side to indicate what failed and why. So to identify what triggered the 5xx/4xx error, check server logs to find messages the server logged before it sent the error.
As far as CORS error messages go, it’s expected that in most cases for a 5xx or 4xx error, servers won’t add the Access-Control-Allow-Origin response header to the response; instead the server most likely will only send that header for 2xx and 3xx (redirect) responses.
So if you get the cause of an 5xx/4xx error solved such that you can get a success response, you may find your CORS config is already working fine and you’ve got nothing left to fix.
I had the same issue, the server doesn't support cross origin request. The API developer should change Access-Control-Allow-Origin to * (means from any origin).sometimes jsonp request will bypass, if its not working, google chrome provides plugins to change origin
plugin

Categories

Resources