Express.JS: Attach cookie to statically served content - javascript

I use Express.JS to serve static content:
express.use(express.static('./../'));
When index.html is served, I would like to send a cookie alongside the response indicating if the user is signed in or not. Normally one should use res.cookie() but I cannot see how to use it for statically served content.

Not sure why you need to do this, but you can place your own middleware before the static module.
The following quick hack should work:
function attach_cookie(url, cookie, value) {
return function(req, res, next) {
if (req.url == url) {
res.cookie(cookie, value);
}
next();
}
}
app.configure(function(){
app.use(attach_cookie('/index.html', 'mycookie', 'value'));
app.use(express.static(path.join(__dirname, 'public')));
});
The above inserts another function in the chain of middleware express uses before the static middleware. The new layer attaches the cookie to the response if the URL matches the specific one you are looking for -- and passes the response further down the chain.

Consider also the following approach:
If your express is behind web-server you can serve static files without bothering express - it should be faster than via middle-ware. If you use nginx, this can help: Nginx Reverse Proxying to Node.js with Rewrite.
Assuming that your static file has javascript in it, you can also set cookies directly on the client side only requesting from express the data you need for this cookie:
document.cookie = "user_id=" + user_id;
Flanagan's JS definitive guide (edition 6!) has an excellent coverage on how to use cookies in client-side javascript (in addition to being the best among JavaScript books :).
It can be a trivial advice, but I have seen the following flow (more than once): client sends API request (which has a cookie attached to it, obviously), server gets data from the cookie and serves the response completely built on the data contained in this cookie. All this instead of just quietly reading this cookie in the client. Basically client asks the server what it has in its own cookie.
In your scenario you need to request user_id/access_key only once and then always check the cookie in the client, going to the server only for the data that client doesn't already have, but storing and checking session state and, maybe, some compact data used in most pages (such as username, e.g.) in cookies locally (you can also cache data in local storage, to reduce the server load even further). In this case, express won't even know if a user accidentally refreshes the page (if you don't change URLs to reflect application state as well, of course, or only change #-part).

As app.configure was removed since Express.js v4, I would like to do an update.
For Express.js versions > 4, to initialise my app by passing options inside the express.static(root, [options]) method, in which you can pass a Set-Cookie header in the property called setHeaders:
app.use(express.static(publicPath, {
setHeaders: function (res, path, stat) {
res.set('Set-Cookie', "myCookie=cookieValue;Path=/")
}
}));
It is important to set Path=/ because otherwise express will create numerous duplicates of the cookie on the client side.

Related

can someone please explain REQ in express plz

I dont get how we use req in express. I undrstand that the server can respond back to client,but when it comes to req object im confused. Is req when the server is asking for somethong from the client?
HTTP is an application, client-server protocol. Everytime that a client want the server to perform an action, it has to make a request. The HTTP protocol defines a set of actions or verbs that are available to the client so it can make each request using one specific verb (GET, POST, PATCH, PUT, DELETE, etc). It doesn't matter what verb the client uses, only the client can initiate a comunication with the server using one of that verbs. So this is how exactly an HTTP GET request looks like:
GET / HTTP/1.1
Host: example.com
User-Agent: curl/7.69.1
Accept: */*
The first line contains the verb used, in this case GET, the path requested, in this case /, and the protocol version, in this case HTTP/1.1. The next lines, are a set of key value pairs called the headers of that request, which can define a lot of aspects of the request made by the client to the server. By the way, an HTTP server never could or will start a request to a client, a client always is the one that make the request, and the server is always the one that response that request. One of the aspects of that request for example, is the destination host, that is present in the header host with the value of example.com. Bellow of the headers, all the HTTP requests have a blank line and then the body of the request, which normally contains the data that is sent from the client to the server. In this case, no data body is sent on the request.
Express is an HTTP server based on the HTTP module available on Node.js. Express simplifies the way that the native Node.js HTTP server works. Here is tipically how an Express app looks like:
const express = require('express');
const app = express();
// This is called a router
app.get('/path', (req, res) => {
// This router will perform some action with the req object
// And will send a response to the client
});
So, on the example above, the method app.get(...), available on Express applications, allows the server to deal with the GET requests that come from the client. The app.get() method takes two arguments, a path and a callback function. The path argument represent the string that goes after the name server, for example, in the URL www.example.com/test, the hostname is www.example.com, and the path is /test. That method app.get() is also called a Router. So, the router of the example will deal with the GET requests to that server which also define /path value as the path the request is sent to. Once a request to the server fit those two conditions, that callback will be triggered.
So, finally we get to the answer. The res variable is an object (a set of key-pair values separated by commas and locked into curly braces), that contains the data of the HTTP request, into a friendly legible object. For example, if you want to print to the console the path that the client used, you can print it like this console.log(req.path), or you can get all the headers of that HTTP request, you can use console.log(req.headers). The req object is one of the 5 main objects in Express, in fact the Express documentation defines a ton of methods that you can use with the request object (req). To get deep into the request object, you can see the official Express documentation in this link. The callback defined into the router, can use the req object, to extract information of the client's request, process it and return a response to the client later.
With an express server, you get two objects passed to a request handler.
req is data about the incoming request (things that were sent from the client). It contains the headers on the request, it contains a parsed query string, it contains the URL path, it's generally the object where middleware puts things for request handlers to use. While Express adds a bit more to this object, you can see the general concept of the req object by looking and the http.IncomingMessage object documented here. This is what the object starts out as and then Express adds more to it. The express version of the object is documented here.
res is the response object. This is all about sending a response. It will hold the outbound headers you want to send with the request. It contains the methods you use for sending a response. The core object is an http.ServerResponse object documented here and then Express adds some more things to the object on top of that which is document here.

Node JS : Allow only server side calls to my api

I have been racking my brains for a simple solution.
Lets say, I have 10 API endpoints in my Node JS application.
I have already allowed 3 of them to be public, the remaining 4 have JWT based authentication
Now I have 3 more routes, which will not have JWT and I need to only allow Server side calls. No browser or curl or postman, should be able to call them. How do I identify from the request object that it is originating from a server?
Or to put it in another way, how to I reject all cross origin calls to my api? As server side does not fall in CORS, they should filter through
----- EDIT -----
I recently came across a service that uses User Agent header to block server side calls.
Can i enforce User Agent header for my service and ensure that the header does not have browser agents. This can be hoodwinked easily, but as a theoretical solution, what would be the nodejs interceptor that discards requests whose user agent refers to a browser agent?
You can use the express-ipfilter package and only apply it to certain routes you want to protect:
const express = require('express'),
ipfilter = require('express-ipfilter').IpFilter;
// Whitelist the following IPs
const ips = ['127.0.0.1'];
// Create the route
app.get("/securePath", ipfilter(ips, {mode: 'allow'}), (req, res) => {
// only requests from 127.0.0.1 (localhost/loopback) can get here
});
app.get("/openPath", (req, res) => {
// all requests can get here
});
app.listen(3000);
If you are using Node behind a proxy, you may need to configure the proxy to set a header with the actual IP and then pass the ipfilter function a function in the detectIp property to the second parameter.
Let's say you are using nginx and have it configured to send the original IP through the x-Real-IP header, you can pass this function to ipfilter:
const express = require('express'),
ipfilter = require('express-ipfilter').IpFilter,
ips = ['127.0.0.1'];
app.get("/securePath", ipfilter(ips, {mode: 'allow', detectIp: getIp}), (req, res) => {
// only requests from 127.0.0.1 (localhost/loopback) that go through the proxy can get here.
});
app.get("/openPath", (req, res) => {
// all requests can get here
});
app.listen(3000);
function getIp(req) { return req.headers["X-Real-IP"] }
You should use a similar authentication/authorization as for the routes that have JWT authentication from the clients.
This means that the caller service should also authenticate using a JWT token, having a special role of service or something like that (this is 100% your decision on what convention you choose). That token should be signed by the caller and verified by the receiving microservice.
This solution has the advantage that it does not depends on the infrastructure, it works the same no matter where the services are deployed.

NodeJS: Send HTTPS request but get HTTP

I am building a website using NodeJS, and I deploy it to Heroku. But when I open the website, something went wrong. Here is the problem:
Code:
In the main source file of my web:
app.get('/', (req, res) => {
var data = {
rootURL: `${req.protocol}://${req.get('Host')}`,
};
res.render('home.html', data);
});
Then, in home.html, I include the following script:
<script type="text/javascript">
$.getJSON('{{rootURL}}'+'/about', {}, function(data){
// Code here is deleted for now.
}).fail(function(evt) {
// Code here is deleted for now.
});
</script>
Here I use hbs template, so {{rootURL}} is equal to the 'rootURL' property within the 'data' object rendered along with the 'home.html' page.
The '/about' is one of the APIs I designed for my web. It basically sends back something about the website itself and this information is wrapped in JSON.
Then, here comes the problem. The code works fine locally, and works well when I send HTTP request instead of HTTPS to Heroku. But if I send HTTPS request to Heroku, I'll get 'Mixed Content' Errors:
Errors I get in Chrome Console.
I then switched to 'Elements' tab in the developers tool, and I saw this:
The schema is HTTP, not HTTPS!
I'm very confused here. I just grab the 'protocol' property within the 'req' object, and fill in the template with it. So, I'm assuming if I enter '[my-website-name].herokuapp.com' with 'https' schema in my Chrome Browser, my nodeJS app deployed on Heroku should get 'https' for req.protocol. But Apparently it's not the case. What is wrong here?
I assume you don't actually have an SSL certificate? Heroku will be providing the HTTPS, but it will then translate it to normal HTTP internally when it hits your express endpoint, which is why it sees req.protocol as HTTP.
Is there any point in even providing the URL to getJSON? Why not just send it $.getJSON('/about', callback) and let the browser handle that?
Also, you haven't hidden your URL in that first image you uploaded, if that's what you were intending.
Heroku router is doing SSL termination, so no matter if you connect via http or https, you get http on your side. Original protocol is however set in X-Forward-Proto header. You need use this value.

What is the best way to access the JWT from node?

I have implemented JWT authentication using Node.js. When the user signs in, Node.js signs/creates a JWT and sends it back. Thereafter, it is stored in the localStorage. Now, this is probably where I am going wrong, but... to move forward, I make use of the express router, and within the router code (which is obviously at the node level) I want to be able to access the token (which is in localStorage) so that I can make a call to the API for further data. However, I just realised that localStorage is at the client-end and that node/express/router doesn't recognise localStorage. So I am stuck. Obviously, I am doing something fundamentally wrong... I should not need to access localStorage from the express router file. Perhaps, I should really be making the API calls not from the express router file, but from client side.
Any hints/directions?
localstorage is bad way to save token. you should save token in cookies and use then where you want.
EXAMPLE:
new Cookies(req,res).set('access_token',token,{
httpOnly: true,
secure: true // for your production environment
});
and then read:
var token = new Cookies(req,res).get('access_token');
You need to send the JWT that is stored on the client side every time you make an API request to the server side.
https://jwt.io/introduction/
Scroll down to the section How do JSON Web Tokens work? The JWT should be sent in the header of the API calls in the form:
Authorization: Bearer <token>
How you do this depends on how exactly you'll send the HTTP requests to the API, but it should be pretty simple in any respects. You can find out about how to add Headers to an angular $http request at this link:
https://docs.angularjs.org/api/ng/service/$http
Then it's up for each of your authenticated express routes to check the headers, pull the JWT out, ensure that it's valid, and then proceed with the request (or halt it if the JWT is invalid).

Whitelist PDF Embed

Is there a way or a service that allows for read-only (no saving or downloading) PDF embeds on one domain only? I know that there are services like Scribd and Slideshare but the problem is that while they do have private options, no service as far as I can tell allows to whitelist embeds (eg, only allow embeds on certain domains.) Vimeo can do this with videos and I don't mind paying for this service either. Any ideas?
I've also looked into PDFJS and it seems they have a NodeJS implementation so I was thinking maybe PDFJS could grab the PDF from the server on the server side and just stream it to the client without exposing the original PDF url. However I couldn't find good documentation for PDFJS.
Any help would be greatly appreciated.
This can be achieved with any HTTP server, but since you mentioned Node in your question, we will solve the problem with that technology. I am assuming Express Framework as well.
First you simply host the PDF as a static file on your server. Then you would register some Middleware that detects a request for the PDF. If the hostname that is requesting does not match a list of "approved" domains, then you serve an error back to the client. If the domain is approved, you serve the PDF. This is no different then a .htaccess file in Apache that limits access by domain/IP or an "allow" block in a Nginx config. Here is a quick look at the Middleware function...
var approved = []; // Add your approved domains here.
// Make sure this middleware comes before app.use(express.static)
app.use(function(req, res, next){
if(req.url == '/path/to/PDF') {
if(approved.indexOf(req.headers.host) {
next();
} else {
next(new Error('Nu uh uh!'));
}
} else {
next();
}
});
This way even if they copy the embed code, they will get an error from the server (probably should be a 403, but those are semantics you can decide on yourself)

Categories

Resources