Create cookies on other domains via javascript - node.js

I'm working on a project where I need to create a cookie in another domain of my application, I know that doing it directly is not possible because that would be a security flaw.
Example scenario:
Frontend: epictv.cf
Streaming Backend: ipv4-epictv001.infra-imm.epictv.cf
Reason: I need a <video> tag to be pre-authenticated in the streaming domain, since you can't pass any type of header in the tag.
For that I thought of making the frontend make a request to the backend and pass in the "body" of this request (GET) the value of the cookie I want to create, but for some reason when axios makes this request the cookie is not created, in however, if i open the route manually works fine!
How could I get the frontend to place a cookie on the backend?
My attempt code:
async createCookie(req, res){
const session = req.params.session;
res.cookie("sessao", session, { maxAge: 1000000 });
res.status(200).json({
"status": "ok"
});
},
PS: I know that in the video tag I could pass the url with the authentication in the src itself, but I would rather not do it.

Related

What is the optimal way to secure JWT in cookies for a React/Redux application?

Right now I'm working on a React/Redux full stack application and I'm working on setting up JWT auth and passing the JWT via cookies. I had a couple of questions on handling the CSRF token generated by the server.
1) Once you set the CSRF token on the server side, does it then get passed to the client? How exactly does it get passed? (I've seen examples where its passed in as an object, but the ones ive found weren't explained very well or just scarce)
server.js
// config csrf in server
app.use(csrf({
cookie: {
key: '_csrf',
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 86400
}
}))
// Hits my api routes, and if these arent hit, the index.html file is rendered
app.use(routes)
// Route used to fetch the index html file
app.get('*', (req, res) => {
let csrfToken = req.csrfToken()
console.log(csrfToken) // This doesnt console log anything on the server side
res.sendFile(path.join(__dirname, "./client/build/index.html"), {
_csrf: csrfToken
})
})
2) Once the CSRF token is set, should it be stored in the state of the application (Redux store) for persistent storage? Or would this be unnecessary?
3) On the client side, when I'm ready to submit data to a route via POST request, if I understand correctly, you'd have to include the input hidden field with the csrf variable like so:
<input type="hidden" name="_csrf" value=csrfToken/>
So when you submit a form, you'd include that input, then in the post request (assuming fetch or axios), you'd set the headers to include that csrf token, that way the server can compare it to the token the client is submitting to the route, am I understanding this correctly?
Thank you!
None of what you’ve asked specifically relates to react or redux. This is about request / response exchange with an HTTP server.
When using the the CSRF middleware, it automatically provides a CSRF tokens as a session cookie on request, and you’re expected to provide that back to the server on further requests.
1) CSRF tokens are usually set in a cookie by the server, or set as meta tag in the HTML. This code is generated uniquely per HTTP request to the server. It’s the applications responsibility to read the cookie/meta tag and then send it back to the server for future requests. One possible way is as a header: ‘X-csrf-token’ (https://en.m.wikipedia.org/wiki/Cross-site_request_forgery)
2) unnecessary in some cases: but that’s only by virtue of the fact that if the server sends a cookie header response, then your browser will always store that cookie, unless you have cookies turned off. When sending a request to the server, you need to retrieve that cookie and send it as the header above
3) I suggest you read the readme for express CSRF middleware (https://github.com/expressjs/csurf/blob/master/README.md), particularly this part about how the middleware looks for the CSRF tokens in responses or further requests:
The default value is a function that reads the token from the
following locations, in order: • req.body._csrf - typically generated
by the body-parser module. • req.query._csrf - a built-in from
Express.js to read from the URL query string.
• req.headers['csrf-token'] - the CSRF-Token HTTP request header.
• req.headers['xsrf-token'] - the XSRF-Token HTTP request header.
• req.headers['x-csrf-token'] - the X-CSRF-Token HTTP request header.
• req.headers['x-xsrf-token'] - the X-XSRF-Token HTTP request header.
As you can see - how you provide it back to the server is up to you — most people choose a header, but it can be as a body or a get request query string.

how to use passport SAML with both node (express) as backend and vue as client

I have an app with node (express) backend, and vue client.
I'm trying to add SAML SSO using passport. (makes sense to do it on the server node app).
it works perfect when used in express app. but when I applied it to a structure of express backend and vue client - it fails to make the redirection to the Idp.
when user enters my login page, vue client (Login.vue) calls node backend for verifying the user. (api verifyuser)
node call passport.authenticate('saml', ...) and I expected a response I can send back to the vue function that called me, and there, in Login.vue - to make the redirection.
but here comes the problem:
in the backend node app, the redirect response is sent after my code is executed, inside passport strategy. So it is sent automatically to the browser, not returning to the vue script that called this node api.
So the redirection is done in the background, the user don't see any redirect. the original login page is still shown.
And my vue function gets the response back from the API - only after the browser sends the redirect (in the background) to the IDP, and gets the login html page response from the IDP.
So the data I get back - is an html of the IDP login page, instead of a redirection data.
How can I solve it?
I'm new to client technologies and js and node including, so I really don't know how such a flow should be handled. searching 3 days for solution.
Thanks a lot for you assistance!
here is my snippets of code:
Login.vue:
<input class="button wide cropBottom io-mango ae-5 margin-top-0 toRight" v-on:click="userLogin" type="button" value="Log In"/>
...
userLogin: function() {
...
...
$(".overlay").show();
this.$http.post(process.env.BASE_URL + "verifyuser", oUser) //call backend node express app
.then(function(data) {
...
here I gets only an html login page which the IDP sent as a response to the redirect with the SAML Request.
}
Backend node express app:
verifyuser.js:
module.exports = function (app) {
app.post('/verifyuser', (req, res, next) => {
var SamlStrategy = passportSaml.Strategy;
passport.use(new SamlStrategy(
{ ...
});
passport.authenticate('saml', {session: false}, function (err, user, info) {
...
})(req,res,next);
//tried to get the redirect here, but res still don't have it. only after this function is called, the SAML request is created from the req, and the location url is made.
});
I've found a solution.
I changed the Vue client:
instead of calling the server using ajax, and expecting a data response to come back,
I called the server using post of a form.
that way, the browser redirects to the server when I call it, and when the passport library in the server returns a redirect response- it is done in the forground, and the user can see it.
In Single logout, passport have done a better job:
the passport API just returns the logout request created.
then I can decide myself if I want redirect from the server, or I want to send the redirection request to the waiting client function - and do the redirection from there.

In an Express.js server, how can I send an HTML (with style and js) acquired from a HTTP request, as a response?

This is an Express.js server. I'm trying to authenticate my Instagram API.
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const axios = require('axios');
const ejs = require('ejs');
var app = express();
// bodyparser middleware setup
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var instagramClientId = '123123';
app.get('/instagram', (req, res) => {
axios({
method: 'post',
url: `https://api.instagram.com/oauth/authorize/?client_id=${instagramClientId}&redirect_uri=REDIRECT-URI&response_type=code`,
}).then((response) => {
res.send(response.data);
console.log(response.data);
}).catch((e) => {
console.log(e);
});
});
// port set-up
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`app fired up on port ${port}`);
});
This is the error I got. Looks like the html file was sent just fine, but the css and js weren't executed. You can see the error messages were all about style and js not being excuted.
Is this because I need to enable some options in my res.send() code?
I'm going to answer two questions here, the first is what I think you're actually having problems with and the second is what would technically be the answer to this question.
What I think your actual problem is: A misunderstanding of OAuth2.0
Looking at your code, it looks like you're trying to get a user to authenticate with Instagram. This is great, OAuth2.0 is fantastic and a good way to authenticate at the moment, but you've got the wrong end of the stick with how to implement it. OAuth2.0 is about redirects, not proxying HTML to the user. In this case it looks like you're using axios to make a server side call to the instagram OAuth endpoint and then sending the user that HTML. What you should actually be doing is redirecting the user to the Instagram URL you've built.
A high level of the "dance" you go through is the following.
The user requests to login with instagram by pressing a button on your website.
You send the user to an instagram URL, that URL contains your applications token plus an "approved" redirect url. Once the user has logged in with Instagram, Instagram will redirect the user to your approved redirect url.
The users browser has now been redirected to a second endpoint on your server, this endpoint recieves a one-time token from Instagram. You take that token on your server side and use axios (or similar) to make a server side request to fetch some user information such as their profile. Once you have that data, you can then create a user in your the database if needed and issue a new session token to them. Along with the profile call on this, you'll also get a token given directly to you (different from the one the users browser gave you) which will allow you to make requests to the Instagram API for the privileges you requested from the user originally.
This means you have 2 endpoints on your service, the "hello, I'd like to log in with instagram, please redirect me to the instagram login page" and then "hello, instagram said I'm all good and gave me this token to prove it, you can now check with them directly" (this is the callback endpoint).
You can manage this whole process manually which is great for understanding OAuth, or you can use something like Passport.js to abstract this for you. This lets you inject your own logic in a few places and handles a lot of the back and forth dance for you. In this instance, I'd probably suggest handling it yourself to learn how it all works.
Ultimately, you are not sending the user any HTML via res.send or anything similar. Instead your first endpoint simply uses a res.redirect(instagramUrl). You also thus do not make any HTTP requests during this portion, you do that on the "callback" after they've entered their username and password with Instagram.
Technically the correct answer to this question: proxy the JS and CSS calls, but this is really bad for security!
You're sending some HTML from a 3rd party in this case. So you will need to also allow the user access to the HTML and CSS. Security wise, this is quite iffy and you should really consider not doing this as it's bad practice. All of the JS and CSS links in the page are most likely relative links, meaning they're asking you for some JS and CSS which you are not hosting. Your best bet is to find these exact paths (ie: /js/app.min.js) and to then proxy these requests. So you'll create a new endpoint on your service which will make a request to instagrams /js/app.min.js and then send that back down with res.send.
Again, please do not do this, pretending to be another service is a really bad idea. If you need something from instagram, use OAuth2.0 to authenticate the user and then make requests using their tokens and the official instagram API.

Connect NodeJS as client to third party service that uses session data

I am developing a website in Node.JS / Express, and have until now used JWTs to store authentication data.
To summarize, I have an AngularJS app which calls a REST service on Node, and for authentication the user POSTs username and data to the server and gets a JWT containing the username and expiration, which then gets sent along with every request which requires authentication.
Now, though, I need to be able to connect to a third party service (which is a REST service that runs on Delphi) which uses sessions to save authentication data instead.
Using Fiddler, I can see that the service, when used in another implementation (third party) responds with JSON authentication data. In all subsequent requests, the client sends a cookie called dsessionid, although it doesn't appear in the "response cookies" in the previous response.
My question is: how do I take that dsessionid cookie in my NodeJS app and put it in my JWT so I can send it to my actual client?
I managed to solve my problem by getting the session ID in the "Pragma" header of the response (I don't know if the header is something "default" for Delphi applications or if it was specific to this application, I had to look through Fiddler entries to find out what header had the data) and then using a custom cookie jar with the request module to put the session ID in the cookies of subsequent requests.
const request = require('request-promise-native')
return request.get({
url: 'http://example.com:20202/auth',
resolveWithFullResponse: true
})
.then(res => {
return res.headers['pragma']
})
.then(sid => {
let j = request.jar()
j.setCookie(request.cookie('sessionid=' + sid), 'http://example.com')
return request.get({
url:'http://example.com:20202/fetchData',
resolveWithFullResponse: true,
jar: j
})
Hope this helps somebody.

Protect non-api (res.render) route with express-jwt token in Node.js

First of all, I have read all tutorials on protecting REST API routes with jwt (express-jwt & jsonwebtoken), and it works fine for that purpose.
This works fine:
app.use('/api', postApiRoute);
And this also works, somewhat, I mean.. it does verify the token when I use it to show a webpage with angular http request calls, but when you add expressJwt({secret: secret.secretToken}), you cannot just access localhost:3000/api/post anymore. The expressJwt({secret: secret.secretToken}) is the problem here.
app.use('/api', expressJwt({secret: secret.secretToken}));
app.use('/api', userApiRoute);
What I really need is to protect a non-json but html/text request route with jwt like eg.:
app.get('/admin*', expressJwt({secret: secret.secretToken}), function(req, res){
res.render('index', {
//user: req.session.user, <- not sure how to do the equivalent, to extract the user json-object from the express-jwt token?
js: js.renderTags(),
css: css.renderTags()
});
});
.. without having to make http requests in angular/js, but using express' render function.
I need to do this since my application has 2 primary server routed views, so 1 where admin scripts are loaded from, and 1 where the frontend (theme) assets gets loaded.
I cant however get jwt/tokens to work with server rendered views, only json api requests.
The error i'm getting is: "UnauthorizedError: No Authorization header was found"
Couldn't find any information about (server rendered views protected with jwt, only serverside api requests and client side angular/ajax http requests) this, so I hope my question is clear, and that I do not have to fall back to using sessions again.
Not sure if I understood correctly, but if you are talking about entry html routes (i.e., loaded directly by the browser and not by you angular app), then you simply have no way of instructing the browser as to how to set the authorization header (no without introducing some other redirect based auth flow).

Resources