set secure cookie in sails.js app - javascript

What is the way to configure sails.js to set secure cookies? We are using redis to persist session state. The sails.js prescribed way (rather than some Express middleware option) is desired. Ultimately, I want the "secure" column in the Chrome cookies view to be checked for the app's cookie:
In the docs, there is no explicit mention of how to do this:
http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.session.html
There is an ssl config option, but deploying the app with ssl: true did not produce the desired result:
module.exports.session = {
...
ssl: true
...
}
The ssl option isn't documented either, but I assume it has something to do with signing cookies instead.
edit: in the screen shot, I'm serving from localhost without HTTPS, but this app is being served from a production server using HTTPS and the same behavior is observed

Sails uses express.session to handle session cookies, therefore you can enable secure cookies by setting cookie: { secure: true } in config/session.js
You need to use HTTPS for express to set the cookie
it requires an https-enabled website, i.e., HTTPS is necessary for secure
cookies. If secure is set, and you access your site over HTTP,
the cookie will not be set.
If you are behind a proxy that does SSL termination on behalf of your web server enable express trust proxy option by adding the following middleware in config/http.js
module.exports.http = {
customMiddleware: function(app) {
app.enable('trust proxy');
}
};

It appears that there is not a way to do this currently. If you look at the sails.js session implementation here (https://github.com/balderdashy/sails/blob/98522d0bc5df5e6bc30b4dc35708ae71cf4625e2/lib/hooks/session/index.js) you'll see that there is, in fact, no secure-mode stuff whatsoever :(
Since sails is using their own session store implementation, and not piggybacking off of node-client-sessions or express-sessions, the only way to solve this (I think) would be to submit a PR to the sails people.
Sorry!

You can set signed cookies like so
Adding a signed cookie named "chocolatechip" with value "Yummy:
res.cookie('chocolatechip', 'Yummy', {signed:true});
Retrieving the cookie:
req.signedCookies.chocolatechip; //"Yummy"
check out the sails Documentation

Related

Not saved cookie in chrome with mysql and express js [duplicate]

I am using the express-session module, it works perfectly on localhost but on my website (hosted on Heroku using Cloudflare), the express session is being blocked as being a third party cookie. Here is the configuration for my session:
app.use(session({
resave: false,
saveUninitialized: false,
proxy : true,
cookie: {
maxAge: 3600000000000,
httpOnly: false,
secure: false,
domain: '.mydomain.com',
path: '/'
},
store: sessionStore,
secret: 'mysecret',
unset: 'destroy'
}));
Is this an issue with Express or maybe Cloudflare/Heroku?
#Why the cookie is blocked
From whatis.techtarget.com:
A third-party cookie is one that is placed on a user’s hard disk by a
Web site from a domain other than the one a user is visiting.
As you mentioned in your comment, your client and your server are on different domains:
www.castcrunch.com is my client side server's URL and cast-crunch-server.herokuapp.com is my backend server URL
You can read more about cookie domains in the RFC 6265:
The Domain attribute specifies those hosts to which the cookie will be sent.
#What you could do about that
As mentioned in this dzone article, you could use Json Web Tokens to do the authentication. Your server would send the token in the login response body, the client would store it and send it to the server in every subsequent request header.
The drawback with this approach, since you are storing the token, is that you would become vulnerable to XSS attacks. You have to pay special attention to that: sanitise all inputs, or better yet, use frameworks and languages that already to that.
Note: Of course, you could also uncheck the "block 3rd party cookies" option in the browser settings, but this does not seem like a long term solution :).

ExpressJS: When authenticating, do I store the JWT token from the backend or the frontend?

I am inheriting a backend Express API and a front end React app.
Currently I am using cookie-parser in my POST /login API like so:
res.cookie('something', 'abc123', {
maxAge: COOKIE_MAX_AGE
});
on my front end app, there is a function for checking if an auth token exists:
export function isAuthCookiePresent() {
console.log('ALL COOKIES:', cookies.get());
return (
cookies.get(AUTH_COOKIE_NAME) && cookies.get(AUTH_COOKIE_NAME) !== null
);
}
And as expected I see { something: 'abc123' } in my console logs.
However, when I try logging in this using autodeployed branches in Vercel (https://vercel.com/), the cookie is missing.
I was under the impression that cookies were supposed to be set on the front end? But in the code the cookie is being set on the backend. And I don't see anything in the code that passes it to the front end. I thought I would find something on the front end like that would have a "upon successful login, execute cookies.set("x-auth-token", res.body.token)"
It's odd to me that it works locally at all. Would someone mind explaining how this works? I thought cookies were stored in the browser on the client side. But if that was true, why does cookie-parser even exist in express and why is it being used server side?
However, when I try logging in this using autodeployed branches in Vercel (https://vercel.com/), the cookie is missing.
This is because it appears you are setting the cookie server side, and as far as I know vercel only handles client side and will not let you use express.
I was under the impression that cookies were supposed to be set on the front end? But in the code the cookie is being set on the backend. And I don't see anything in the code that passes it to the front end. I thought I would find something on the front end like that would have a "upon successful login, execute cookies.set("x-auth-token", res.body.token)"
Cookies can actually be set through headers (Set-Cookie: <cookie-name>=<cookie-value>), which is what express's res.cookie does. MDN's article on the Set-Cookie header says:
The Set-Cookie HTTP response header is used to send a cookie from the server to the user agent, so the user agent can send it back to the server later. To send multiple cookies, multiple Set-Cookie headers should be sent in the same response.
It's odd to me that it works locally at all. Would someone mind explaining how this works? I thought cookies were stored in the browser on the client side. But if that was true, why does cookie-parser even exist in express and why is it being used server side?
Cookies are, in fact, stored client-side. They are accessible through client side javascript and backend with the cookie header. The cookie-parser module is needed to parse the name=value syntax sent by the Cookie header (Cookie - HTTP | MDN). It's being used server-side becuase validating cookies in the frontend can let any user give a false "true" value to your if statement that you use to validate cookies.
As an answer to the question: I recommend backend because JWTs have to be signed, and setting and signing them client-side will let anyone sign an arbitrary payload.

CORS policy error while calling remote URL in Angular

Try to call remote API Url but, getting Access-Control-Allow-Origin error. I tried many things like following but, nothing works.
proxy.conf.js
const PROXY_CONFIG = [
{
context: [
"/api/planets"
],
target: "https://swapi.co",
secure: false,
changeOrigin: true,
logLevel: "debug",
bypass: function (req, res, proxyOptions) {
req.headers["Access-Control-Allow-Origin"] = "*";
req.headers["X-Forwarded-Host"] = "localhost:8090";
req.headers["X-Forwarded-For"] = "localhost";
req.headers["X-Forwarded-Port"] = "8090";
req.headers["X-Forwarded-Proto"] = "http";
}
}
];
module.exports = PROXY_CONFIG;
Running with ng serve --port 8090 --proxy-config proxy.conf.js
Can't make any changes in server side because I am using third party API.
Try adding plugin like https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?hl=en in your chrome browser.
Since you cant change the server side config, so this plugin can do the trick. The browser by default blocks CORS
Since You cannot make any changes on remote server. So it can be escaped using Reverse proxy server. I also faced the same issue while calling linkedin services.
a. There is an https://cors-anywhere.herokuapp.com/ you can append this before your url
and it will temporarily resolve CORS issues.
Since in enterprise scenario you can not use herokuapp.com before your application specific names so better to set below proxy server.
b. Second approach is using rever-proxy approach and set up your own server (local or remote ) for reverse proxying.
https://stackoverflow.com/q/29670703/7562674
You can also implement reverse-proxy like implementation using Spring and Jersey.
https://github.com/hhimanshusharma70/cors-escape
As the error says, a header named Access-Control-Allow-Origin must be present in a CORS response.
Since swapi.co responses include the Access-Control-Allow-Origin header for correct CORS requests (can be tested with a simple fetch('https://swapi.co/api/planets/') from your browser's dev console), the issue may be because of your proxy settings.
Try modifying the response in the proxy bypass method:
bypass: function (req, res, proxyOptions) {
...
// Note that this is "res", not "req".
res.headers["Access-Control-Allow-Origin"] = "*";
...
}
You can't! End of story. If the owner of the api has decided not to allow cross origin requests then you can't. If your are not going to host your app on the https://swapi.co domain then you will not be able to use the api directly from Angular and you will need some kind of pass through api call on the server from .NET, Node, PHP, Java etc.

Is there a way to obtain user data if the Keycloak authentication is done on Apache level, not front-end application

Generally, there are at least 2 options of securing applications using Keycloak OpenID Connect stack:
Use it on the application using Keycloak adapters (in my case, a SPA javascript front end)
Use it on Apache using mod_auth_openidc
If I choose to use number 2, how can I obtain the user data (username, for example)?
------------------------Edit due to #Cyril Dangerville answer -----------------
While I understand the general approach, my way is seemed very forced.
Now my authenticated, my request has session cookie and access token headers, but cannot access any header due to being initial page load
Perform an call to any protected resource to get access Header value
Use the access token to call the userinfo end point (But this is on another domain so the cookie wont get submitted)
Can you help me by explain where I should go here?
With mod_auth_openidc, you pass user data to applications as Apache environment variables and/or HTTP headers. The latter is useful if using Apache as reverse proxy for remote apps (mod_proxy). The proxy case is addressed briefly in mod_auth_openidc project's FAQ.
You can find more details about how to configure this translation of OpenID Connect token claims - including the authenticated user data - to environment variables/headers in the configuration file: auth_openidc.conf; two properties in particular:
For the REMOTE_USER variable: OIDCOAuthRemoteUserClaim <claim-name> [<regular-expression>]
For others: OIDCPassClaimsAs [none|headers|environment|both].

NodeJS, Express, why should I use app.enable('trust proxy');

I was needed to redirect http to https and found this code:
app.enable('trust proxy');
app.use((req, res, next) => {
if (req.secure) {
next();
} else {
res.redirect('https://' + req.headers.host + req.url);
}
});
I'm using heroku to host my project, I noticed that heroku as default issued *.herokuapp.com cert, so I can use http and https as well.
When looked at req.secure within app.use callback, without app.enable('trust proxy'), req.secure is always false, when I add app.enable('trust proxy') it's false for about 2 times and after the https redirection it's switches to true.
app.enable('trust proxy'), the docs:
Indicates the app is behind a front-facing proxy, and to use the
X-Forwarded-* headers to determine the connection and the IP address
of the client.
My question:
Why would my server be behind a proxy?(is it relates to the issued *.herokuapp.com cert?), if someone could explain how all fits together, I mean, why my server is behind a proxy? and why without app.enable express won't identify(or accept) secure connection?
If your not running behind a proxy, it's not required. Eg, if your running multiple websites on a server, chances are your using a Proxy.
X-Forwarded-For header attributes get added when doing this so that your proxy can see what the original url was, proxying in the end will be going to localhost you see. The reason why it's needed is that X-Forwared-For can be faked, there is nothing stopping the client adding these too, not just a proxy. So trust-proxy should only be enabled on the receiving end, that would be behind your firewall. Because you have control, you can trust this.
So in a nutshell, if your website is running behind a proxy, you can enable it. If you website is running direct on port 80, you don't want to trust it. As the sender could pretend to be coming from localhost etc.

Categories