How can you use cookies with superagent? - node.js

I'm doing cookie session management with express with something like this:
req.session.authentication = auth;
And I verify the authenticated urls with something like
if(!req.session.authentication){res.send(401);}
Now I'm building tests for the URLs with mocha, superagent and should, however I can't seem to find a way to get/set the cookie with superagent. I even tried to request the login before the authenticated test but it is not working,
I have tried adding the request to the login in the before statement for the mocha BDD suite, however it is still telling me that the request is unauthorized, I have tested the authentication doing the requests from the browser, however it is not working from the suite any ideas why?

Use superagent.agent() (instead of plain old superagent) to make requests have persistent cookies. See 'Saving cookies' in the superagent docs, or the code examples: agency.js, controller.test.js.

Seems like following code works fine;
req.set('Cookie', "cookieName1=cookieValue1;cookieName2=cookieValue2");

If the issue is in sending cookies for CORS requests use .withCredentials() method
described here
request
.get('http://localhost:4001/')
.withCredentials()
.end(function(err, res) { })

Since you mentioned you need to both get and set the cookie:
Get:
const request = await Superagent.get('...')
const cookie = request.header['set-cookie']
Set:
Superagent.post('...').set('Cookie', 'cookie_info')

2020 +
A clean way to do it is:
create a simple cookie store
abstract set Cookie to send it in each request
update the cookie only when needed
Note I keep the same URL because I use graphql but you can make it a parameter:
const graph = agent =>
agent.post('/graph')
.set('cookie', cookieStore.get());
const handleCookie = res =>
cookieStore.set(res.headers['set-cookie'][0]);
let currentCookie="";
const cookieStore = {
set: cookie=>{currentCookie=cookie},
get: cookie=>currentCookie,
};
module.exports = {graph,connectTestUser,handleCookieResponse};
You can now just use graph(agent) to send a request and handleCookie(response) when you have a response that may update your cookie (set or clear), example:
graph(agent).end((err,res) => {
if (err) return done(err);
res.statusCode.should.equal(200);
handleCookie(res);
return done();
});

Add a cookie to agent cookiejar:
const request = require('superagent');
const {Cookie} = require('cookiejar')
const agent = request.agent()
agent.jar.setCookie(new Cookie("foo=bar"))

Related

How do I access Express.js Cookie in React app?

I'm creating E-shop with MERN Stack
This is my response from the server on Login where you can see, the cookie is SET and it's sent from the Backend.
That means no there shoudln't be problem with BE, but the FE I will need to handle the Cookie on the FE.
How do I access this sent Cookie from Express in the React ?
I have tried something like this:
const handleLogin = async (event) => {
event.preventDefault();
try {
const url = "http://localhost:5000/api/auth/login";
const data = await axios.post(url, formFields);
const { user } = data.data;
// Here I have tried to access it from Headers where I can see it in the attached
// picture under Set-Cooki. But inside headers I can only see
// Content-Length and Content-Type
console.log(data.headers);
// Aswell I have tried react-cookie but docs are not clear enough for me.
// and this just sets cookie from react, I would like to use cookie from express
// and set it like this
// await setCookie("user", "INSERT_HERE_COOKIE_FROM_EXPRESS.JS", {
// path: "/",
// });
setCurrentUser(user);
await resetFormFields();
} catch (error) {
const data = error.response.data;
!data.error
? alert(`${data.message}`)
: alert(`${data.message}: ${data.error}`);
}
};
Thank you for any answers, I'm sure it's not that hard as I think and it's few lines of code.
As I see on your screenshot - you use express with httpOnly cookies:
https://developer.mozilla.org/ru/docs/Web/HTTP/Cookies -
A cookie with the HttpOnly attribute is inaccessible to the JavaScript Document.cookie API; it's only sent to the server. For example, cookies that persist in server-side sessions don't need to be available to JavaScript and should have the HttpOnly attribute. This precaution helps mitigate cross-site scripting (XSS) attacks.
And I think you don't want to use nonsecure cookies in your E-shop - so you can't access it, but you can use custom headers, so on your frontend it will be like:
fetch('/myapi').then(response => console.log(response.headers.get('myCustomHeader')));

Send a SAML request by POST using saml2-js in Node

I've gone through the documentation (however limited) to connect to an IDP. It's all configured and working properly except one thing. The IDP won't accept SAML Requests via GET.
Does saml2-js support HTTP POST for sending SAML requests to the IDP and if so, how is this coded? If not, is there an alternative NPM package that would work?
Currently i have:
sso.sp.create_login_request_url(sso.idp,{},(err, login_url, requestId) => {
console.log('err',err)
console.log('login_url',login_url)
console.log('requestId',requestId);
response.redirect(login_url);
});
An addition to jsub's answer:
The POST request to the IdP must be made by the browser, not by the server (by needle in jsub's case). Only the browser contains the IdP session cookie which authenticates the user with the IdP. res must contain an HTML page with an auto-submitting <form> with one <input> per param:
app.get("/login", function(req, res) {
sso.sp.create_login_request_url(sso.idp, {}, function(err, login_url, requestId) {
var url = new URL(login_url);
res.type("html");
res.write(`<!DOCTYPE html><html>
<body onload="document.querySelector('form').submit()">
<form action="${url.protocol}//${url.host}${url.pathname}" method="post">`);
for (const [param, value] of url.searchParams)
res.write(`<input name="${param}" value="${value}"/>`);
res.end(`</form></body></html>`);
});
});
I am trying to work around this as well, and my attempts have not worked but the approach is to make a separate http POST request with a client (using needle in my case) and then try to pipe the response from that into the response for the handler, e.g. something like this:
sso.sp.create_login_request_url(sso.idp, {}, (err, login_url, requestId) => {
// response.redirect(login_url);
const [url, param] = login_url.split("?")
const postOptions = {
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}
needle.post(Url, param, postOptions, (err, postResponse) => {
postResponse.pipe(res)
});
However I am not having much luck, trying to dig into why the pipe does not work
EDIT: the piping seems to work when I do it in this short form
needle.post(url, param, postOptions).pipe(res)

Using cookies with axios and Vue

I have created a Node.js express server that connects to Salesforce.com using the SOAP interface provided by 'jsforce'. It uses session cookies for authorization via the 'express-session' package. So far, it has a POST method for login and a GET to perform a simple query. Testing with Postman has proven that this server is working as expected.
As the browser interface to this server, I have wrttien a Vue application that uses axios to perform the GET and POST. I need to save the session cookie created during login POST then attach attach the cookie to subsequent CRUD operations.
I have tried various methods to handle the cookies. One method I have tried is using axios response interceptors on the POST
axios.interceptors.response.use(response => {
update.update_from_cookies();
return response;
});
The function 'update_from_cookies' attempts to get the cookie named 'js-force' but it does not find it although I know it is being sent
import Cookie from 'js-cookie';
import store from './store';
export function update_from_cookies() {
let logged_in = Cookie.get('js-force');
console.log('cookie ' + logged_in);
if (logged_in && JSON.parse(logged_in)) {
store.commit('logged_in', true);
} else {
store.commit('logged_in', false);
}
}
I have also seen various recommendations to add parameters to the axios calls but these also do not work.
I would appreciate some advice about how to handle cookies using axios or some similar package that works with Vue
Thanks
The problem has been resolved. I was using the wrong syntax for the axios call
The correct syntax has the {withCredentials: true} as the last parameter
this.axios.post(uri, this.sfdata, {withCredentials: true})
.then( () => {
this.$router.push( {name : 'home' });
})
.catch( () => {
});

better way to intercept requests that nodejs further make

I have created a nodejs server A with the express framework. I have used request-promise module to make http requests to different server B. Browser makes call to server A with cookie data. This cookie contains the jwt token that I further want to pass to server B.
#Get("/users")
getUsers( #Cookie('token') token: any): any {
let usersPromise = Users.getUsers(jwt);
return Promise.all([usersPromise])
.then(response => {
return response.users;
});
}
I have created a Users class that further call server B using the request-promise module. One way is to pass the jwt token directly to every calls like this as I did in
let usersPromise = Users.getUsers(jwt);
is there any other way some intercept way to do this?
I have superagent package to intercept my all the request and appended the jwt to header.
TO configure this
Install superagent and superagent-use modules
npm install superagent superagent-use --save
Require the modules
var request = require('superagent-use')(require('superagent'));
Then define the superagent middleware
// interceptor used by superagent to add jwt in header for each request
request.use((req) => {
req.header.jwt = jwt;
return req;
});
and then to make calls
request
.get(url)
.query({ view: 'jsonView' });
Superagent is more useful than the request-promise as this module provide the promise and rxjs base apis , url prefix and an elegant way to append querystring.

Can I send a GET request with cookies in the headers in Node?

In a browser, if I send a GET request, the request will send the cookie in the meanwhile. Now I want to simulate a GET request from Node, then how to write the code?
Using the marvelous request library cookies are enabled by default. You can send your own like so (taken from the Github page):
var j = request.jar()
var cookie = request.cookie('your_cookie_here')
j.add(cookie)
request({url: 'http://www.google.com', jar: j}, function () {
request('http://images.google.com')
})
If you want to do it with the native http:request() method, you need to set the appropriate Set-Cookie headers (see an HTTP reference for what they should look like) in the headers member of the options argument; there are no specific methods in the native code for dealing with cookies. Refer to the source code in Mikeal's request library and or the cookieParser code in connect if you need concrete examples.
But Femi is almost certainly right: dealing with cookies is full of rather nitpicky details and you're almost always going to be better off using code that's already been written and, more importantly, tested. If you try to reinvent this particular wheel, you're likely to come up with code that seems to work most of the time, but occasionally and unpredicatably fails mysteriously.
var jar = request.jar();
const jwtSecret = fs.readFileSync(`${__dirname}/.ssh/id_rsa`, 'utf8');
const token = jwt.sign(jwtPayload, jwtSecret, settings);
jar.setCookie(`any-name=${token}`, 'http://localhost:12345/');
const options = {
method: 'GET',
url: 'http://localhost:12345',
jar,
json: true
};
request(options, handleResponse);

Resources