I've been trying to get my frontend and backend to share cookies but the server never actually get them.
my frontend has credentials include on it
const res = await fetch('http://localhost:5000/v1/auth/register', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
and my backend have my core like
app.use(
cors({
origin: 'http://localhost:3000',
credentials: true,
})
);
and they still don't send cookies!
even tho I have a route that sets the cookie on the frontend from the backend
res.cookie('auth-token', token, {
httpOnly: true,
maxAge: 86400,
});
and it works perfectly fine after I used cors.
my check auth middleware:
exports.verifyAuth = async (req, res, next) => {
try {
const token = req.cookies['auth-token'];
if (!token) {
return res.status(401).json({ msg: 'No token, authorization required.' });
}
const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
req.user = decodedToken.user;
next();
} catch (err) {
res.status(401).json({ msg: 'No token, authorization required.' });
}
};
EDIT:
I was debugging it and apparently its always the first ever time that it doesn't send the cookies and that's because I'm using getInitialProps to send the request but I'm guessing that the request happens before cookies are loaded so I'm trying to find a way to pass the cookies to the request manually because fetch doesnt.
Try this config: {withCredentials: true}
Related
When users login, I send an axios post request to the login endpoint with its required credentials(accessToken). everything works fine. After a successful login, they are redirected to the homepage where I make i get request. The request doesn't send the credentials whixh of course would return an unauthenticated error. Even when I specify this in the axios get request it still woudn't work.
withCredentials: true
on postman and Insomnia, the token is sent successfully and the correct data is gotten, but It just will not work on the web. What could be wrong?
ths is the useFetch code
try {
await axios({
url: `https://crayonnne-jotter-server.herokuapp.com/api${url}`,
method: "get",
withCredentials: true,
}).then((res) => {
console.log(res)
});
} catch (err) {
console.log(err)
}
You have to provide the accessToken through the headers.
axios({
... // other stuff
headers: {
Authorization: `Bearer ${accessToken}`
},
})
I am currently working on a project using Ionic React with .NET API for login process.
And this is the problem I am facing:
This is the Response Header of my post request
And when I try to look at the application cookie, it seems that it is not being set.
This is the application view which should see the jwt cookie has been stored.
I have already added these two params for my Axios post request but not work at all.
{withCredentials: true, credentials: 'include'}
Thank you for your time to look into my question or help!!!
Below are my request/response setting on the client-side and backend:
Axios request:
const api = axios.create({
baseURL: `https://localhost:7220/api/User`
})
api.post("/login", postData, {withCredentials: true, credentials: 'include'})
.then(res => {
console.log(res);
})
.catch(error=>{
console.log(error);
})
Controller:
Response.Cookies.Append(key: "jwt", value: token, new CookieOptions
{
HttpOnly = true
});
Response response = new Response { Status = true, Message = _LOGINSUCCESSFUL };
return Ok(response);
Program.cs:
builder.Services.AddCors(p => p.AddPolicy("corsapp", builder =>
{
builder.WithOrigins("http://localhost:3000").AllowCredentials().AllowAnyMethod().AllowAnyHeader().AllowAnyMethod();
}
)
);
I am using ReactJS and ExpressJS with jwt authenticate. In my server, I have config for cors like this
const corsOptions = {
//To allow requests from client
origin: true,
credentials: true,
methods: ['GET', 'PUT', 'POST', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization', 'Set-Cookie'],
};
In my client, I send request to the Server like this
export function createNewRequest(data, callback) {
axios.post(`${process.env.REACT_APP_API}/api/requests`, data,
{
withCredentials: true
}).then(res => {
callback(res.data);
})
.catch(err => {
if (err.response) {
if (err.response.status === 403 || err.response.status === 401) {
getToken(createNewRequest(data, callback));
} else {
callback(err.response.data);
}
}
})
}
In my local environment, I test and every thing run fine. But when i deploy my server, then i try to send request from my local client to the server. The server doesn't receive cookies in headers.
I have tried setting origins like this
const corsOptions = {
//To allow requests from client
origin: ['http://localhost:3000'],
credentials: true,
methods: ['GET', 'PUT', 'POST', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization', 'Set-Cookie'],
};
And tried to set default withCredentials
axios.defaults.withCredentials = true;
But none of these work. Can anyone explain to me what i did wrong and help me solve this
Try to allow app.use(cors()); like this without option(to allow everything).
example of code:
app.use(cors());
app.use(bodyParser.json({ origin: "https://famegoal.com/" }));
app.use("/function", couponRoutes);
mongoose
.connect(
`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASSWORD}#cluster0.qvs4c.mongodb.net/${process.env.DB_NAME}?retryWrites=true&w=majority`
)
.then(() => {
app.set("port", process.env.PORT || 5000);
app.listen(app.get("port"), function () {
console.log("Node app is running on port", app.get("port"));
});
})
.catch((err) => {
console.log(err);
});
That's not safe, but it's a great solution.
set the following middleware in your app.js as follows
app.use(function(req, res, next) {
res.header('Content-Type', 'application/json;charset=UTF-8')
res.header('Access-Control-Allow-Credentials', true)
res.header(
'Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type,
Accept'
)
next()
});
and in reactjs use withCredentials: true
The Setup
I have setup a frontend environment using create-react-app. In this environment I use Axios to make a POST request to my Node JS Express Backend Server /login endpoint. I setup sessions middleware using express-sessions and storing the sessions in Redis. I have all this running in localhost currently.
Environment
React App - http://localhost:3005/kp (Note: the service runs on
http://localhost:3005 however, all the routes have /kp in them)
Express Backend - http://localhost:5001
Redis - http://localhost:6379
What Works
When the frontend sends the request to the backend the Express server does it's thing and authenticates the user; it stores the username in the req.session.username (this is just as a test), Redis console shows that the key value store was successful, the frontend network tab shows a 200 status with a Set-Cookie response header and a tab that shows the cookie (screenshots below).
The Problem
Everything seems to be working fine but the cookie is not set in the Browser. I have refreshed the page, tried again many times and yet it will not set the cookie in any browser (Google Chrome & Safari). I am getting frustrated because it seems as though Chrome acknowledges that the Set-Cookie is present but ignores it for some reason.
What I've Tried
Axios
I have tried setting withCredentials: true - Does not work
Verified the cookie with Set-Cookie is being sent back to the frontend after the POST request
Backend
I have checked my CORS policies to but they seem fine; however, I am not great with CORS so there could be misconfiguration there
Tried setting credentials to true in CORS policy
Verified the session with variables are being set with Redis.
Code
React Frontend Axios POST Request
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
}
},
{ withCredentials: true }
)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
this.setState({
errorMessage: `Server Error`,
loading: false
});
});
Express Server
const express = require('express');
const http = require('http');
const cors = require('cors');
const socketServer = require('./src/sockets');
const bodyParser = require('body-parser');
const session = require('express-session');
const redis = require('redis');
const redisClient = redis.createClient();
const redisStore = require('connect-redis')(session);
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
const port = process.env.PORT || 5001;
const { loginRoutes } = require('./src/routers');
const app = express();
redisClient.on('error', (err) => {
console.log('Redis error: ', err);
});
app.use(cors({
origin: '*',
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
credentials: true
}));
// Redis session storage setup
// API Docs for express-session: https://www.npmjs.com/package/express-session
const sessionMiddleware = session({
secret: process.env.REDIS_SECRET || 'testing12345',
name: 'session',
resave: false,
saveUninitialized: true,
cookie: {
secure: false
},
store: new redisStore(
{
host: process.env.REDIS_HOSTNAME,
port: process.env.REDIS_PORT,
client: redisClient,
ttl: 604800
}
)
});
// Uses session middleware
app.use(sessionMiddleware);
app.use(bodyParser.json({ limit: '5mb' }));
const server = http.createServer(app);
// Starts Socket Server
socketServer(server, sessionMiddleware);
// Uses the routes from the router directory
app.use(loginRoutes);
server.listen(port, () => {
console.log(`Listening on port: ${port}`);
});
Screenshots
Network Response
Request Cookie
Application Cookies
As you can see the cookie is missing in the list of browser cookies. I have a feeling it is something small but I have not been able to find anything.
I am not getting any errors in any service. Thank you in advance for your help.
Solution
As MichaĆ Lach pointed out I put withCredentials in the wrong place in the Axios call.
Frontend Axios
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
})
However, once I did this I began to get CORS error. The CORS error was you cannot have a wildcard '*' in your Access-Control-Allow-Origin (origin) configuration. For this example I changed it to point only to http://localhost:3005; however, there are ways to do dynamic whitelists as documented here: https://www.npmjs.com/package/cors#configuring-cors-w-dynamic-origin
Backend
app.use(cors({
origin: 'http://localhost:3005',
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
credentials: true
}));
Once I made these changes the cookie started being set on the frontend correctly.
Are you sure, you are setting axios options correctly ?
You have :
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
}
},
{ withCredentials: true }
)
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log(error);
this.setState({
errorMessage: `Server Error`,
loading: false
});
});
Try this:
axios.post('http://localhost:5001/login', loginBody, {
headers: {
'Content-Type': 'application/json'
},
{ withCredentials: true }
}
....
I have a React app, and an API. When i POST data to APIs login url API responses me back with cookie on successful login, which I have to set, so in each next request user will send this cookie. But I can't find a method to get it from response.
I want to set sessionid, but I can't reach it within code. I tried to do
Cookies.set('sessionid', response.headers['sessionid']);
But it sets undefined. console.log(response.headers) also gives me {content-length: "31", content-type: "application/json"}. Do I do something wrong?
Sender function:
formSender() {
const url_to_send = `${this.state.api_base_url}:${this.state.api_base_port}${this.state.api_user_url}/login/`;
axios.post(url_to_send, `username=${this.state.username}&password=${this.state.password}`, {headers: {'Content-Type': 'application/x-www-form-urlencoded'}})
.then((response) => {
// I need to set the cookie here
this.setState({
login_success: response.status === 200,
request_sent: false
});
})
};
Try to set Access-Control-Expose-Headers in the back end or
await axios({
method: 'post',
url: YOUR_URL,
data: Data,
headers: { 'Authorization': 'TOKEN' }
});
I have the same problems and i do that for resolve in backend:
app.use(cors({
origin: true,
credentials: true
}));
and the axios request :
axios({
method: "post",
url: `http://localhost:5500/api/user/login`,
withCredentials: true,
data: {
email,
password,
},
headers: {
"Content-Type": "application/json",
}
})
.then((res) => {
console.log(res);
})
I was initially looking for a solution to setting a cookie from a response, but I realized if it's passed as a Set-Cookie header then it is set by the browser. No need to set it manually. Here is the console view
My app looks something like this:
const app = express();
app.use(cors({
origin: ['http://localhost:3000'],
methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
credentials: true,
}))
app.use(cookieParser())
app.get('/foo', verifyToken, (req, res) => {
// you can omit verifyToken if you want, it's for bearer auth.
if (true) {
res.cookie('XSRF-TOKEN', 'example')
res.send('Welcome')
} else {
res.sendStatus(403);
}
});
The React side:
<Button onClick={() => {
axios.get('http://localhost:8081/foo', {
params: {},
headers: {
Authorization: `Bearer 123`,
// again, omit ^ if you're not doing bearer auth
},
withCredentials: true,
}
).then((response) => {
console.log('cookie should be set')
})
}}>Express cookie</Button>
Bear in mind if you're deploying to a server both react and express should be on an https connection. Connecting http <-> https causes other issues with cookies.