Not able to get cookie from Node to React - node.js

I created a simple login system where after certain user logs in the backend I set profile cookie with jwt token value
res.cookie('profile',jwt_token,{
secure : false,
httpOnly : true
});
In React frontend I am sending a get request to Node backend where I expect to get that jwt token
const { data } = await axios.get('http://localhost:2000/users/test', {withCredentials:true});
This is my controller for getting a cookie
export const test = async (req,res) =>{
try {
const cookie = req.cookies.profile || "no cookie";
res.json(cookie);
} catch (error) {
console.log(error.message);
res.status(406).json({success:false});
}
};
When I try to get a cookie after logging in with Postman I get cookie value but when I try to get the cookie from React through axios i am getting 'no cookie'. I've also set app.use(cors()) in Node

Apparently a known Axios bug exists that can be solved like this. Just add this line of code and try again.
axios.defaults.withCredentials = true;
const { data } = await axios.get('http://localhost:2000/users/test', {withCredentials:true});

You might need to install the cookie-parser middleware http://expressjs.com/en/resources/middleware/cookie-parser.html and then add it to your app:
const cookieParser = require('cookie-parser');
//...
app.use(cookieParser())

Related

When the browser send cookies not received from the express server

I'm Developing a full-stack web application with Node js and express js as the backend and using Next Js for the front end and JWT for the authentication, I'm setting the JWT token with the cookie in the browser. The cookie is set successfully in the browser, but whenever I try to get the cookie from the Express server to check whether the user is valid or not, the cookie does not receive from the browser. I tried several ways to get the cookie from the browser but it doesn't respond. but it is receiving the cookie token from the Postman/thunder client.
note: The frontend port is 3000 and the backend port is 5000.
You can suggest another way for the user authentication with next js with external express server.
res.cookie("userToken", token, {
expires: new Date(Date.now() + 9000000000),
})
and the JWT verify code is here
const jwt = require("jsonwebtoken");
const jwtToken = (req, res, next) => {
try {
const userToken = req.cookies?.userToken;
if (userToken) {
const verify = jwt.verify(userToken, process.env.JWT_SECRET);
req.user = verify;
}
next(); // for getting the api result back to client
} catch (error) {
next(error);
}
};
module.exports = jwtToken;

Cookies do not stored when set it with axios POST method

I'm trying to write and read cookies and falling into a problem below.
This is my basic server side:
server.js
const app = express();
app.use(cors());
app.use(cookieParser());
import routes from '...';
app.use("/foo", routes);
app.listen(8888);
routes.js
const routes = express.Router();
routes.post('/', (req, res) => {
res.cookie("myFoo", "abcd");
res.send("Cookie added");
}
});
routes.get('/', (req, res) => {
res.send(req.cookies.myFoo);
}
});
export default routes;
And my client side at "http://localhost:3000".
I do two HTTP request
POST http://localhost:8888/foo
GET http://localhost:8888/foo
And get the response exactly what I expected abcd. Also, the cookie exists in the browser tab Application > Cookies too.
The problem cases when axios is used in the client.
const api = axios.create({
baseURL: "http://localhost:8888/foo"
});
async function setCookie(object) {
return api.post("/", object)
.then((res) => {
return res;
});
}
function getCookie() {
return api.get("/")
.then((res) => {
return res;
});
}
setCookie({})
.then((res) => {
getCookie();
})
The api.post() run usually and the header response Set-Cookie is correct. But cookies in the browser tab Application > Cookies are empty. Also, api.get() get the undefined.
I did try to move res.cookie() or the set cookie job in server side to GET route it WORKS on both HTTP and axios
routes.get('/', (req, res) => {
res.cookie("myFoo", "abcd");
});
tldr: Set cookie in HTTP POST method work fine but when client use axios to call so it causes problems.
Can you show me why this happened? And which code part went wrong that caused me into this?
Cookies are only used in cross-origin Ajax requests when:
The client asks to use them
The server grants permission to use them cross origin
So you need to change the client side code to ask for them:
const api = axios.create({
baseURL: 'http://localhost:8888/',
withCredentials: true,
});
And the server code to grant permission (note that you can't use credentials at the same time as the wildcard for origins).
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));

Slack OAuth HTTP Post Request returns "undefined" access token

I'm using the following code in a simple slash command app to handle OAuth for public distribution of my app:
const express = require("express");
const bodyParser = require("body-parser");
const fetch = require("node-fetch")
require('dotenv').config();
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
// App installation handling
app.get("/auth", async (req, res) => {
if (!req.query.code) {
console.log("Access denied!");
return;
}
var data = {form: {
client_id: process.env.SLACK_CLIENT_ID,
client_secret: process.env.SLACK_CLIENT_SECRET,
code: req.query.code,
redirect_uri: "https://6c0c-35-20-201-50.ngrok.io/auth"
}};
console.log(req.query.code);
// Send received code back to Slack and get Oauth2 access token
const config = {
method: "POST",
body: data,
headers: {'Content-type': 'application/x-www-form-urlencoded'}
};
console.log("We got something!");
try {
const slack_oauth_response = await fetch("https://slack.com/api/oauth.v2.access", config);
console.log("Access token granted!");
console.log(JSON.stringify(slack_oauth_response.access_token));
} catch (e) {
console.error(e);
}
res.sendStatus(200);
})
When I try using the Add to Slack button, I get a timeout error. My log results will look like this:
PS D:\Documents\SlackRegApp> node local_testing.js
1007612862405.3292595223126.481b3e25d2c29dc80af7dc21bcb84a8bc19c28ddec155a429c6651105903902f
We got something!
Access token granted!
undefined // where the access token should be
If I go ahead and just log the entirety of slack_oauth_response, it looks like this:
{"size":0, "timeout":0}
When I try to install the app via cURL, it works, like below:
curl -F code=1007612862405.3292595223126.481b3e25d2c29dc80af7dc21bcb84a8bc19c28ddec155a429c6651105903902f -F client_id=**SLACK_CLIENT_ID** -F client_secret=**SLACK_CLIENT_SECRET** https://slack.com/api/oauth.v2.access
Hoping for some help here, thanks!
I just used the Slack WebClient API to access the oauth.v2.access method instead of trying to make my own HTTP request.

Can't store JWT in Cookie with Express & Angular

I have been pulling my hair out the last couple of days. No matter how many google searches I make I can't find an answer so I come here as a last resort in hope of some help.
I am creating a full stack application on the MEAN stack. My login works. It is verifying that the email and password is matching a user's email and password in my database. Now I want to send a JWT token to my client so I can keep the user signed inn. I understand how JWT works and I have generated one already
const ACCESS_TOKEN_SECRET = "a random string";
const payload = {"username": login_result[0].username};
const accessToken = jwt.sign(payload, ACCESS_TOKEN_SECRET);
This is where my problems start. I want to store the token in a cookie, to prevent XSS attacks. I have tried all kinds of ways to store the JWT in a cookie. Most forums wrote that I should do
res.cookie('access_token', accessToken);
As I understand, this should automaticly store the JWT in a cookie, on my client, under the name "access_token". However this does not work. When this line is in the code, nothing is happening. By "nothing is happening" I mean that the client code does not execute.
If a password/email is innvalid, I return an error code.
if(res.msg == "403"){
this.showLogErrorMsg = true;
}
This part works.
The else statement looks like this
else{
console.log("Valid username and password");
window.location.href = "http://localhost:4200/profile";
}
Meaning, if the log in is wrong, it will print an error (and it does), if the log in is correct, they are suppose to get redirected. This does not work. It did work when I did
ret.json({"access_token":accessToken});
but does not work with
res.cookie('access_token', accessToken);
This is what I don't understand. It does not store the access_token in cookies and it does not execute the code inside the else statement. There are no error messages on my server or client. Further more, every guide or tutorial says to use the res.cookie, since I am using Express as my webserver.
I have even tried adding the following options:
res.cookie('access_token', accessToken,{domain: domain, path: '/',httpOnly:false,
secure:false,sameSite:false});
The solution is to either, somehow make the res.cookies work, which I really want to do due to it being "what everybody else is using" and it seems really chill. Or, send the JWT token as res.json and then save the token to a cookie in angular. However, does this open you up for XSS? And if not, how can I save something to a cookie in angular?
Thank you guys in advance.
This is a basic express app that sets, unset, and displays cookies.
set GET /login
unset GET /logout
display GET /
This is not dependent on the client (angular)
# main.js
const express = require('express')
const cookieParser = require('cookie-parser')
const app = express()
app.use(cookieParser())
const port = 3000
const accessToken = 'XXXXXXXXXXXXXXXXXXXXX';
app.get('/', (req, res) => {
res.json(req.cookies)
});
app.get('/login', (req, res) => {
res.cookie('access_token', accessToken, { path: '/', httpOnly: true, sameSite: "strict" })
res.send('"access_token" cookies was set !')
});
app.get('/logout', (req, res) => {
res.cookie('access_token', accessToken, { maxAge: 0 })
res.send('"access_token" cookies was unset !')
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
});

Adonisjs - Add basic auth to Static server middleware?

Is there a way to protect statically served assets in adonis via basic auth?
It's not possible to add middleware to route that will hit statically served files from /public dir...
So, for example:
I have /public/docs/index.html
after serving adonis and hitting localhost:3333/docs I'll get content of index.html
I want to browser to prompt basic auth so I tried adding:
Route.get('/docs').middleware(['auth:basic'])
This will not work due: http://adonisjs.com/docs/4.0/http-context#_request_flow
Beacuase serve static is inside Server middlewares which happens before route hit.
Any ideas how to achieve this?
After writing this question I realized I just need to write my own server middleware that will run before static middleware... So I ended doing this:
app/Middleware/Server/StaticAuth.js
'use strict'
const auth = use('basic-auth')
const config = use('Adonis/Src/Config').get('auth.staticAuth')
const validConfig = config && config.protectedUrls.length
class StaticAuth {
async handle({request, response}, next) {
// if there is no valid config... skip this middleware
if(!validConfig) return await next();
// check if currently visited url is matching protectedUrls
if(!request.match(config.protectedUrls)) return await next()
// access native node request/response
const req = request.request
const res = response.response
// gather credentials
const credentials = auth(req)
if (!credentials || credentials.name !== config.username || credentials.pass !== config.password) {
res.statusCode = 401
// send Basic Auth header so browser prompts user for user/pass
res.setHeader('WWW-Authenticate', `Basic realm="${config.realm || 'Protected Area'}"`)
res.end('Access denied')
}
await next()
}
}
module.exports = StaticAuth
add this to list of server middlewares inside start/kernel.js
// ... contents of kernel.js file ...
const serverMiddleware = [
'App/Middleware/Server/StaticAuth', // add it BEFORE Static middleware!
'Adonis/Middleware/Static',
'Adonis/Middleware/Cors'
]
add configuration to config/auth.js
// ... contents of auth.js file ...
staticAuth: {
realm: 'Protected data',
username: 'admin',
password: 'somePassword',
protectedUrls: ['/', '/docs']
}

Resources