Axios - Handle request with auto-set cookies - javascript

I have request which by purpose is sending cookie with token. Here is how it looks-like in Postman:
As you can see in Cookies I receive the token I need to be set in browser. If I open the link from Postman request in browser I get cookie set:
When I use this request with Axios in my code, the cookie is not set in the browser. I am suspecting that I am not using it correctly. What I do is I am calling the method:
axios
.get(`${apiAddress}Users?email=${logEmail}&password=${logPass}`)
.then((res) => {
if (res.status === 200) {
console.log(res.data)
}
})
.catch((e) => {
console.log(e)
});
In this way of use, is it possible this method to set the cookie? Am I doing it right?
If the link is setting cookie when it is opened in browser with correct parameters why it is not working when it is called with Axios?

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.

"The attempt to set cookie via Set-Cookie was blocked" with react

I am working on a small project where users authenticate using their email and password before accessing their profile. The backend uses cookies which are set when correct email and password are submitted to the auth API. I have created an instance of axios to handle the api calls and here is how it looks:
// Step-1: Create a new Axios instance with a custom config.
// The timeout is set to 10s. If the request takes longer than
// that then the request will be aborted.
const customAxios = axios.create({
...apiConfig,
timeout: 10000,
withCredentials: true,
// custom headers can be added here as shown below
// headers: { 'api-key': 'eyJz-CI6Ikp-4pWY-lhdCI6' }
});
// Step-2: Create request, response & error handlers
const requestHandler = (request) => {
request.headers["Accept"] = "application/json";
request.headers["Content-Type"] = "application/json";
return request;
};
const errorHandler = (error) => {
return Promise.reject(error);
};
customAxios.interceptors.request.use(
(request) => requestHandler(request),
(error) => errorHandler(error)
);
customAxios.interceptors.response.use(
(response) => responseHandler(response),
(error) => errorHandler(error)
);
The point is, whenever I try to call the auth API with correct credentials, it returns success but the Set-Cookie header in the response has a warning and the cookies are not set in the browser. Here is the warning:
"The attempt to set cookie using a Set-Cookie was block because it had the "SameSite=Strict" attribute but came from a cross-site response which was not the response to the top-level navigation"
Bear in mind that I am testing the API locally on port 3000 while the endpoint is deployed on a testing server using Chrome.
Thanks
Sounds like your dev setup with two different origins is the problem (and hey, your security policies are working!) Disable the SameSite=Strict in development mode, or extend it to also accept cookies from localhost:3000 (the API domain), not just the same domain where the frontend is served. Also make sure this will be disabled only in the dev setup

Auth refresh token not working when the orgin request is a POST method

I have a js client (vuejs) and a backend using DRF both in local.
I use this package to generate the token : https://github.com/davesque/django-rest-framework-simplejwt
I use this package https://www.npmjs.com/package/axios-auth-refresh to handle refresh token logic.
The main goal is to intercept a request when it return a 401 response, perform a refresh token request and then resolve the orginal request with the new token.
It works when the original request is a GET request but not when it is a POST request.
When using a POST request :
The orgin request fall in 401 when the token expire then the interceptor occur but the server respond with 405 method not allowed:
-https://imgur.com/C1tchvb
the method from the request from the interceptor does not match the method in the code shown above (line 3 & 4) : as you can see the server receive the payload from the origin request as method of the request :
-https://imgur.com/nlAknMi
I found this post : App Script sends 405 response when trying to send a POST request
i try to change the headers as advised but it did not work
How is the payload from the orginal resquest becoming the method of the interceptor when the origin request is a Post request with a payload ?
Here the code from the javascript client :
const refreshAuthLogic = failedRequest => axios(
{
method: 'post',
url: 'auth/refresh',
data: { refresh: store.state.token.refresh }
}).then(tokenRefreshResponse => {
store.dispatch('refreshToken', tokenRefreshResponse.data)
return Promise.resolve()
})
const instance = axios.create({
baseURL: '/api/'
})
instance.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${store.state.token.access}`
return config
})
createAuthRefreshInterceptor(instance, refreshAuthLogic)
EDIT
I manage to get it work but i don't really understand:
the problem is related to DJANGO/ DRF and not axios
it seems that when a POST request is done and fail ( here with 401) the server keeped the data.
Here the part i can't explain :
when the request of the interceptor (to refresh token) hit the server, it messes with the data of previous request.
I had to add a middleware in django to clear the body when the request fails with 401 and it worked for me. But it is not a proper solution i guess.
Unfortunately the lib is loosely mantained and it's flawed in some aspects.
Eg: concurrent requests are not correctly queued when the request is sent with and invalid token but the response arrives when a new token is already issued.
As is, if you look at the lib source, you'll find in the very first lines:
/** #type {Object} */
const defaults = {
/** #type {Number[]} */
statusCodes: [
401 // Unauthorized
]
};
This means that only 401 code is managed and the statusCodes are not exported so them remains private.
If you want to continue to use this library you can fork it in order to change what does not fit with your stack or simply copy the source, edit it and use it as a local service.

How do I do a POST request using the Google Chrome Puppeteer library?

Good Day All,
I'm trying to do a POST request using the puppeteer headless chrome library. I can't seem to get the below code to work.
// Get csrf token
let token = await page.evaluate(() => document.querySelector('[name="CSRFToken"]').value);
let postResponse = await page.evaluate(async(token, cookies) => {
let response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
postData : 'CSRFToken=' + token,
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
console.log('Final response');
console.log(postResponse);
I keep on getting an error that the CSRF token has not been set or that the cookie is invalid.
My question is, am I using the correct method in puppeteer to do a POST? If so, is there any way for me to do some debugging that I can see the actual POST request that was sent?
I appreciate any advice or help. Thanks
You are not creating a request body: hence the error. The postData attribute you set on the request object is not any known attribute, so it won't be set on the request either, meaning that the server will never see your CSRF token. You should look into the MDN docs on fetch().
I believe you should be all good by simply replacing postData with body, but it's hard to know without access to your endpoint. For all we know it might require special headers.
Given that you only post normal form data (which is implied by your key=value code), I would also start using the FormData objects provided by your browser to avoid manual coding of implementation details.
const formData = new FormData();
formData.append("CSRFToken", token);
const response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
body : formData,
headers : {
'cookie' : cookies,
/* other headers you need, possibly content-type (see below) */
},
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
Caveat: using the FormData API will always set the content-type of the data to multipart/form-data. If your server for some reason doesn't support that encoding, and you need to use application/x-www-form-urlencoded (see here for difference),
you can't blindly change the Content-Type: you also need to url encode the content.
For debugging I would simply use a normal Chrome instance to see this. You should be able to run the code there and see the network requests in DevTools (where it would be immediately noticeable that you POST an empty request).

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);
}
});
}

Categories

Resources