Explanation
here, I sent one get req to ABC.com/Users/Login using Axios after this I sent a post request to ABC.com/Users/Login with form data and Cookie.
but it does not work properly. It works properly in postmen
My Code
axios.get('ABC.com/Users/Login')
.then(async response => {
console.log("call login page");
let tokenKey = "__RequestVerificationToken";
let tokenValue = "CfDJ8DF1Ubmz1lpEibYtvvnYRTVXaJ-HWILEtqE_A3bGmDrD-yyKyJPbYK7qrcS9AIzezPo5-
tOWmcXs6WgYThZP-5qo1o1XXpalkJDEPnBtnVa7EhaUYbY2XNcANuugyWgkIf3-O2-_f5h7mNu960qGIaM";
const userName="XYZ";
const pass="test#123";
let form=new FormData();
form.append('UserName', userName);
form.append('Password', pass);
form.append([tokenKey], tokenValue);
headers={
'Cookie':response.headers['set-cookie'];
}
await axios.post('ABC.com/Users/Login', form,
{ headers: {...form.getHeaders(),...headers}})
.then(async response => {
console.log(`Login success in ${userName}`);
console.log("response",response.data);
})
.catch(error => {
console.log(error);
});
}
.catch(error => {
console.log(error);
});
In the First Axios call, I got:-
Set-Cookie: .AspNetCore.Antiforgery.b02ILwhXMuw=CfDJ8DF1Ubmz1lpEibYtvvnYRTXz_0rOkGhY6OXEw3d3vsDNG81V4IaMPfVZm5Hk3_icgp_ToLDG9xKu2mcM1VtEOMnSCktfZwG7Dj9_549SUiKht6Yv33pozagGjseFsfXI74wBwu-mMJkzgwfPx3jS4OA; path=/; samesite=strict; httponly
Set-Cookie: ABC.Session=CfDJ8DF1Ubmz1lpEibYtvvnYRTViv4PoRc%2F7jhjXdtCo4m1GZbcMf60xe9sOva27QUGL0BvT2A2SQZaCmrXlj%2FVL9lTvower%2B1lF87MQVTwDQKAFoEODlnPfWEM6SsrqDa0tomlRynXOtyCROBltiwNI27vo3uo4Y8jEn834lZ4OHYG3; path=/; samesite=lax; httponly
I Want to set cookie like this :-
Cookie: .AspNetCore.Antiforgery.b02ILwhXMuw=CfDJ8DF1Ubmz1lpEibYtvvnYRTXz_0rOkGhY6OXEw3d3vsDNG81V4IaMPfVZm5Hk3_icgp_ToLDG9xKu2mcM1VtEOMnSCktfZwG7Dj9_549SUiKht6Yv33pozagGjseFsfXI74wBwu-mMJkzgwfPx3jS4OA; ABC.Session=CfDJ8DF1Ubmz1lpEibYtvvnYRTViv4PoRc%2F7jhjXdtCo4m1GZbcMf60xe9sOva27QUGL0BvT2A2SQZaCmrXlj%2FVL9lTvower%2B1lF87MQVTwDQKAFoEODlnPfWEM6SsrqDa0tomlRynXOtyCROBltiwNI27vo3uo4Y8jEn834lZ4OHYG3
It works in postmen but not in Axios call. Even I used this also but its not working
let cook1 = response.headers['set-cookie'][0].replace(" path=/; samesite=strict; httponly", "");
let cook2 = response.headers['set-cookie'][1].replace("; path=/; samesite=lax; httponly", "");
let mainCookie=cook1 + " " + cook2
// mainCookie .AspNetCore.Antiforgery.b02ILwhXMuw=CfDJ8DF1Ubmz1lpEibYtvvnYRTUh3vyphSzebPn04M1GqaH8KdFgWLSBpj5a06HBUhoYBhWdiWJw7Yy5525ZcZ_WblCjF7AzWbhQl2dFbQTwOmzP3K7oa0CLirsSJYkhIG-fHGizaNo-3cf8YdSiECkGhMM; ABC.Session=CfDJ8DF1Ubmz1lpEibYtvvnYRTVEF0LnEGw51HveT2mRMrzmgbHiPWjs8UiPcGcqUpJBhTG1uBSE5NLG8tBwkW1XcJH3OxPcPPsaB30aaRREgroCkO1jw%2BJY6tavDFE0P9RTmk9%2Bf2CTVwaTWYRQgPGam1CWJfODoyCzHwiIdfl8ciJS
headers={
'Cookie':mainCookie;
}
If you are using axios, set withCredentials to true.
Example:
const api = axios.create({
baseURL: "http://localhost:5000/api/v1",
withCredentials: true,
headers: {
"Content-type": "application/json",
},
});
then in your Node, in cors middleware, set
app.use(
cors({
credentials: true,
origin: "http://localhost:3000",
})
);
If you want to use Cookies with Axios you need to include the withCredentials property.
axios.post('ABC.com/Users/Login', form, { withCredentials: true });
If it were me I would create a new axios instance and use that one for your calls so that its the same instance of axios for all your api calls.
const axiosInstance = axios.create({
withCredentials: true
})
axiosInstance.post('ABC.com/Users/Login', form)
Related
From a VueJS application I'm attempting to do a simple POST to the Twilio API in order to send an SMS. When the POST is executed I receive the following error:
"Access to XMLHttpRequest at 'https://api.twilio.com/2010-04-01/Accounts/AC42exxxxxxxxxxcfa9c48/SMS/Messages' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field username is not allowed by Access-Control-Allow-Headers in preflight response."
The offending code is the following:
sendTwilio(){
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const sFromNumber = process.env.TWILIO_NUMBER;
const sBaseURL = 'https://api.twilio.com';
const phoneNumber = parsePhoneNumberFromString(this.sms.to_number,'US')
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`,
'username': `${accountSid}`
},
sBodyText='Test'
this.SmsUrl = sBaseURL + '/2010-04-01/Accounts/' + accountSid + '/SMS/Messages';
if (phoneNumber.isValid()){
this.sms.formattedPhone = phoneNumber.number;
this.postData = 'From=' + sFromNumber
+ '+To=' + phoneNumber.number
+ '+Body=' + sBodyText
axios.post(`${this.SmsUrl}`, this.postData, {
headers: headers
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
},
Is the problem with the format used for the username in the header or something with my CORS settings?
My CORS settings are as follows:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = [
'http://localhost:8000',
'http://localhost:8080',
'http://127.0.0.1:8000'
]
Twilio uses Basic Auth to do authentication, so in your case when doing your POST using axios you need to do:
const headers = {
'Content-Type': 'application/json'
};
const auth = {
username: accountSid,
password: authToken
}
[...]
axios.post(this.SmsUrl, this.postData, {
auth: auth,
headers: headers
})
I'm not sure how you're using this though. Have a look at the comments of the question. You should never expose your Twilio credentials to the client in a browser application.
Is there any way to attach a header in axios.all method or do we have to attach the header to each request individually.
axios.all([
axios.delete('http://localhost:5000/requests/'+{id}),
axios.post('http://localhost:5000/records/'+{id, response}),
],{
headers: {Authorization: localStorage.getItem('auth-token')}
}).then(res => console.log(res.data))
.catch(err => console.log(err));
Create an axios instance and use the same instance for all requests (recommended)
const axiosInstance = axios.create({
headers: {'X-Custom-Header': 'foobar'}
});
Sample:
const axiosInstance = axios.create({
headers: {
Authorization: localStorage.getItem('auth-token')
}
});
axios.all([
axiosInstance.delete("http://localhost:5000/requests/" + {id}),
axiosInstance.post("http://localhost:5000/records/" + {id, response})
]).then((res) => {
console.log("Response: ", res);
}).catch((error) => {
console.log("Error: ", error);
})
You can set up the default headers for all the requests as given
axios.defaults.headers.common['Authorization'] = token;
After setting this, All subsequent network calls will carry the Authorization header by default. This workaround will help you to provide application global header like Authorization header. You can create separate Axios instance as
const axiosInstance axios.create({
headers: {Authorization: token}
});
You can choose one of the workarounds.
I have already searched a lot, but none of the solutions found work: Cannot send content-type by axios. but if I use the postman interceptor and I 'send' the request generated by axios this time it works: the node.js / express server correctly receives the request and body-parser works normally!
React side:
const API_URL = "http://localhost:8800/auth/";
const headers = {
accept: 'application/json, text/plain, */*',
'content-type': 'application/json;charset=UTF-8'
};
class AuthService {
register(pseudo, email, password) {
return axios.post(API_URL + "signup/",
{ pseudo, email, password },
{ headers: headers})
.then(response => {
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
});
}
server side
const app = express();
app.use(function (req, res, next) {
console.log( req.headers);
next();
});
app.use( bodyParser.urlencoded({ extended: true }), bodyParser.json());
Usually when I use axios I send the headers in a config variable like this and I stringify the body so it sends as JSON object and not a JS object.
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const body = JSON.stringify({arguments});
try {
const res = await axios.post(/url, body, config);
...
Here's a link to the docs for a little more reading about it:
https://github.com/axios/axios
Even though this question is asked several times at SO like:
fetch: Getting cookies from fetch response
or
Unable to set cookie in browser using request and express modules in NodeJS
None of this solutions could help me getting the cookie from a fetch() response
My setup looks like this:
Client
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'same-origin',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
...
function handleSubmit(e) {
e.preventDefault();
registerNewUser({...values, avatarColor: generateAvatarColor()}).then(response => {
console.log(response.headers.get('Set-Cookie')); // null
console.log(response.headers.get('cookie')); //null
console.log(document.cookie); // empty string
console.log(response.headers); // empty headers obj
console.log(response); // response obj
}).then(() => setValues(initialState))
}
server
private setUpMiddleware() {
this.app.use(cookieParser());
this.app.use(bodyParser.urlencoded({extended: true}));
this.app.use(bodyParser.json());
this.app.use(cors({
credentials: true,
origin: 'http://localhost:4200',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
credentials: true
}));
this.app.use(express.static(joinDir('../web/build')));
}
...
this.app.post('/register', (request, response) => {
const { firstName, lastName, avatarColor, email, password }: User = request.body;
this.mongoDBClient.addUser({ firstName, lastName, avatarColor, email, password } as User)
.then(() => {
const token = CredentialHelper.JWTSign({email}, `${email}-${new Date()}`);
response.cookie('token', token, {httpOnly: true}).sendStatus(200); // tried also without httpOnly
})
.catch(() => response.status(400).send("User already registered."))
})
JavaScript fetch method won't send client side cookies and silently ignores the cookies sent from Server side Reference link in MDN, so you may use XMLHttpRequest method to send the request from your client side.
I figured it out. The solution was to set credentials to 'include' like so:
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
After that I needed to enabled credentials in my cors middleware:
this.app.use(cors({
credentials: true, // important part here
origin: 'http://localhost:4200',
optionsSuccessStatus: 200
})
And then finally I needed to remove the option {httpOnly: true} in the express route response:
response.cookie('token', '12345ssdfsd').sendStatus(200);
Keep in mind if you send the cookie like this, it is set directly to the clients cookies. You can now see that the cookie is set with: console.log(document.cookie).
But in a practical environment you don't want to send a cookie that is accessible by the client. You should usually use the {httpOnly: true} option.
I've set up an API with a create user and an auth route. The auth route should set an httpOnly cookie containing a JWT, and should send JSON for the client to store in localhost.
In the front-end I'm doing a simple fetch.
The server responds 200 and with the JSON I expect, but somehow, the cookie doesn't get set.
However, in Postman, the cookie does indeed get set.
Express server
const express = require('express')
const cors = require('cors')
// boilerplate stuff
app.use(express.json())
app.use(cors({ origin: 'http://localhost:3000', credentials: true }))
app.post('auth', (req, res) => {
// fetch user from db, validation, bla bla bla
const token = jwt.sign({ issuer: user.id }, keys.private, { algorithm: 'RS256' })
res.cookie('token', token, { httpOnly: true })
res.json(user)
})
Next.js front-end
const handleSubmit = async (e) => {
e.preventDefault()
try {
const res = await fetch('http://localhost:5000/api/v1/auth', {
method: 'post',
mode: 'cors',
credentials: 'include',
headers: {
'content-type': 'application/json',
'accept': 'application/json',
},
body: JSON.stringify(formState),
})
const data = await res.json()
console.log(data)
} catch (err) {
console.error(err)
setError(err.message)
}
}
'Twas resolved.
I was looking in Session Storage as opposed to Cookies in my devtools.