Cookies for Domain and its Subdomains in Node/ExpressJS - javascript

So what im attempting to do is to set a cookie on domain.com which is available to all subdomains *.domain.com. Im currently using Express 4.x and NodeJS.
At the moment I can set and get any Cookies on the main domain in my case its testing on a local environment via lvh.me:3000 (allowing for local subdomains)
This is bascially what my Express.js App looks like:
// Require all files (express,http,express-session,cookie-parser...)
var api = express()
// Cookie Parser
api.use(cookieParser());
api.use(session({
secret: 'yoursecret',
cookie: {
path: '/',
domain: '.lvh.me:3000',
maxAge: 1000 * 60 * 24, // 24 hours
},
resave: true,
saveUninitialized: true
}));
// CORS
api.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next()
})
// View Engine
api.set('views', './api/views');
api.set('view engine', 'ejs');
api.disable('x-powered-by');
// Stylus
function compile(str, path) {
return stylus(str).set('filename', path);
}
api.use(stylus.middleware({
src: './app',
compile: compile
}));
// Serving Static Content
api.use(express.static('./app'));
// All Routes
require('../api/routes/test.server.routes.js')(api);
// Router
api.get('*', function(req, res) {
//res.cookie('remember', 1, { domain : "lvh.me:3000" });
res.render('index'); // Get all requests to Index. Angular takes over routing.
});
// Return Application
return api;
Cookies are set via Cookie Parser res.cookie('user', 'bobby'); which seem to be fine for going to lvh.me:3000/anything but for boddy.lvh:3000/anything the Cookies are empty.
Am I missing anything here, I thought Cookies would be available across all subdomains? I have read a few Articles/Posts on Stack Overflow but they all seem rather outdated. Any guidance or help is greatly appreciated.
On a side note if i set a cookie within express file it will be available through out the application. For Example:
// Router
api.get('*', function(req, res) {
res.cookie('user', 'jim'); // This can be accessed
res.render('index');
// Get all requests to Index. Angular takes over routing.
});
Any reason why? - This is in the most part because its being set on any/every view. So it still leaves me with the original question.

While setting cookie if your domain name mydomain.com it is not accessible by subdomains. You have to put leading dot (e.g .mydomain.com). In that case cookie will be shared across subdomains

Related

Nodejs local API does not work

I'm doing an university project with NodeJs but I have some trouble in testing it in local.
This is the problem:
I have a GET API "/api/services/names" and the NodeJS server is running on port 8080.
If I test the API with Postmanor by putting the URL in the Chrome bar ("http://localhost:8080/api/services/names") it works fine and I can get my response.
The problem is that if I test it in my local website using fetch() inside this function:
function fetchServicesNames(){
fetch('/api/services/names')
.then(function(response){
return response.json();
})
.then(function(data){
data.map(addServiceLink);
});
}
The Javascript console gives me this error:
Failed to load resource: the server responded with a status of 404 (Not Found)
I noticed that when I hover the console error, it shows the request string "http://localhost/api/services/names" without the port. But I don't think this is the problem because when I deploy the application on the Heroku platform it works fine... the problem is just in localhost (I'm working with a mid 2010 macbook pro with Mac OSX 10.10.2).
Any help is appreciated, thank you in advance.
Edit:
as requested I'm adding here the server code
// server.js for Hypermedia Application project.
// BASE SETUP
//============================================================
// call packages
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(express.static(__dirname + "/public"));
// we use body-parser, so we need to be able to read data either from
// GET and POST:
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// setting the application port to listen
var serverPort = process.env.PORT || 5000;
// --- database connection omitted ---
// API ROUTES
// ================================================================
// first of all: get the Router
var router = express.Router();
/**
* Services names
* /api/services/names - get - get all services ids and names
*/
router.route('/services/names')
.get(function (req, res) {
Service.find({}, 'id name', function (err, services) {
if (err)
res.send(err);
res.json(services);
});
});
// --- Other APIs omitted ---
// REGISTER ROUTES:
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
//===================================================================
app.set("port", serverPort);
app.listen(serverPort, function() {
console.log(`Your app is ready at port ${serverPort}`);
});
at your server page you add
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
before your API's
it might help you for CORS
Dear i suggest you to write total Path like
http://localhost:<your port number>/api/services/names
inside fetch()and u check once
I too tried and i got Success
Hi try modifying the line like fetch('http://'+window.location.host+':8080/api/services/...)

NodeJs, ExpressJs, PassportJs, isAuthenticated returns null even though CORS is enabled

I've got an app which has a front end/website serving logic on server A in Express, and backend logic with POST endpoints written in Express again on server B.
I've got withCredentials set to true on all my AngularJs methods which call the backend.
In the backend I've got this
var cors = require('cors');
var whitelist = 'http://serverA.com';
var corsOptions = {
origin: whitelist,
methods: ['GET', 'POST', 'OPTIONS', 'PUT'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['Content-Range', 'X-Content-Range'],
credentials: true
};
app.options('*', cors(corsOptions));
app.use(cors(corsOptions));
I try logging in from the client side and the login succeeds and redirects to the correct page but the isAuthenticated method on Passport returns false and it redirects me back to the login page.
What do you think the reason is that the session is not being stored on the client side. The cookie value seems to be set correctly (Chrome dev tools.)
Here is some client code. This is a middleware method used to protect pages for authenticated users.
function authenticate_func(req, res, next) {
//return next();
if (req.isAuthenticated())
{
console.log("Login Successful");
return next();
}
console.log('Login Unsuccessful');
res.redirect('/');
};
Here are middlewares I'm using and the order they are used in.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
require('/local_strategy')(passport, my_sql);
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
Am I missing anything?

Angular JS and Node routing/wiring - data only showing after a page refresh

I'm using Node and Anugular, and I have created a RESTful api from my application, and created an angular resource to use this. I'm confused as to how the Angular ui-router directive reconciles with the Node Routing system on the server.
At the moment I have set up my routes/states in ui-router like this:
$stateProvier
.state('admin', {
url:'/admin',
templateUrl:'views/admin.html',
controller: 'adminController'
});
And this loads into the ui-view on my homepage, when I navigate to this url from a link on the loaded page.
HOWEVER, when I manually type in localhost/admin I get the route from Node, rather than the state render through angular.
Now I'd like to Angular to handle all the navigation on my app, and my resource to get the information, even if the address is typed manually into the navigation bar.
I've created a route in Node is for index, which contains my index.html page from angular, which effectively contains the whole app angular code, including all the routing.
My question is, how can I get angular redirect if I manually type the url into the address bar, and still have the data from the $resource.
I'm directing my resource to '/admin' - could this be the problem?
Does this mean that I need to add the contents of /routes/appointments' into the base node file (server.js), and then remove the route? If so then how do i direct my resource to the correct REST api?
app structure
public
-angular app
-app.js //for angular
routes
index.js
appointments.js
models
views
- index.ejs
server.js //node server file
here is my code exerpts
server.js
//standard routing code
var routes = require('./routes/index');
var appointments = require('./routes/appointments');
var app = express();
//configuring Express
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use('/', routes);
app.use('/', appointments);
routes/index.js
var express = require('express');
var router = express.Router();
// ./routes/index.js
router.get('/', function(req, res) {
res.render('index', { title: 'Homepage' });
});
module.exports = router;
routes/appointments.js - this is the basis of my RESTFUL api
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Todo = require('../models/Appointments.js');
/* GET /todos listing. */
router.get('/admin', function(req, res, next) {
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
module.exports = router;
One way to do this is via the Accept header. If the request only accepts JSON then let the request go through to your API. If the request accepts HTML then always serve up your index page. Then once the index page loads angular's router will take care of the rest.
// Angular config - default Accept header for all ajax requests
$httpProvider.defaults.headers.common = {
'Accept': 'application/json'
};
// Middleware in Node to "intercept" non JSON requests
// Place this after express.static middleware but before your route definitions.
app.use(function(req, res, next) {
// keep in mind this applies to all requests, so 404s will need to be handled by your angular app since any url will serve up the index page
if(req.header('Accept') !== 'application/json') {
console.log('serving the index page');
req.url = '/'; // force the url to serve the index route.
}
next();
});
One more thing to note about this approach is that obviously you won't be able to see/debug your JSON data by hitting the URL directly anymore. There are several useful tools like Advanced REST Client or POSTman which actually give you better control and more options for things like that. Just make sure you set the Accept header in one of those tools and you'll be able to see the JSON response.
The actual URL is localhost#!/admin, try that. Angular hides the hashbang #!
Angular's URL routing is an "illusion" in that way. It only works on the client-side and only when your Angular app is loaded, which is on the main / route.
A solution could be to conditionally redirect from localhost/admin to localhost#!/admin, i.e. redirecting to your Angular app and passing it the #!/admin path. The condition could be a check for whether or not JSON was requested.
router.get('/admin', function(req, res, next) {
if(req.header('Accept') !== 'application/json')
return res.redirect('/#!/admin');
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
You'll also need to configure Angular such that when it requests '/admin' json data from the server, it should only accept json (by setting the request header), which is how the the server will distinguish it from the regular '/admin' request. For that, if you're using $http.get you would do $http.get('/admin', {'Accept':'application/json'})

How to post to api from Express.js

I am new to Node/Express and to API's in general. Long story short, I am a front end guy diving into backend and architecture for the first time. The breakdown of my problem is as follows:
App description: A web app that allows users to view medical data records.
Desired feature: Change the state of a json record on page load. When a user opens a record(page), I want to change a json object from UNDIAGNOSED to DIAGNOSED automatically. This needs to be done server side to avoid exposing the api endpoint, which needs to stay hidden for security reasons. Think of it like a 'read/unread' email. Once it has been opened, it changes the state to 'read'
Probelem: ...I am a newb...
//When the server GETs a request to this URL
router.get('/content/:contentid', function(req, res, next) {
// Configure the REST platform call
var platform_options = {
resource: '/content/' + req.params.contentid,
method: 'POST',
json: "diagnosis_state: DIAGNOSED"
};
// Make the call
var platform = ihplatform(_config, req.session, platform_options, callback);
platform.execute();
// Result processing
function callback(error, response, body) {
console.log(response.body);
}
});
I am using a custom HTTP API that was built in-house by another developer. The endpoint for the call is dynamically generated via the re.params.contentid. You will also notice that the call itself is built into the platform.execute function.
There is a bit of copy/pasting going on, as I am trying to modify a working call.
My question is this: How do I make an api POST call to a remote API upon the HTTP request for a certain url via express.js?
Here is what you can do on express.js -
1) write a module for route mappings in a separate js file where all the mappings can be listed. Below is the code snippet of the module file
function mappings(app)
{
var email = require('./routes/emails');// ./routes/emails is js file location exporting UpdateEmail variable which contains function for update
app.put('/email/update', email.UpdateEmail); // mapping url /email/update to exported variable UpdateEmail
}
2) add following statement in app.js file where mapRoutes is a .js file created in step 1
require('./mapRoutes').mappings(app);
3) Below is the sample app.js file
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Credentials', false);
res.header('Access-Control-Max-Age', '86400');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next();
});
app.options('*', function(req, res) {
res.send(200);
});
require('./mapRoutes').mappings(app);
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
4) live website running on above code - kidslaughs.com
I'm not quite sure your question here, because "POSTing from ExpressJS" could mean two different things.
In the most common case, you are making a POST request from a web page. While this might be served or even rendered via Express, the call is originating from the web page. In that case the javascript on the web page is making the post. Common web frameworks for that might be jQuery's $.ajax or Angular's $http. Whatever framework you use, you'll define the data to post, the API endpoint to post to, and what to do with the response.
Another meaning of your question might be that you want your Express app to make a http request from the server side. You will need a package to do so, so that you can make a HTTP programatically. A popular package for this is request.
It's hard to say more without knowing what frameworks you are working with. Keep searching around, you'll figure it out!
I think you're looking for request.js.
var request = require('request');
request.post('/content/' + req.params.contentid').form({json: "diagnosis_state: DIAGNOSED"})

Express session is undefined when accessing external website

I'm trying to use express sessions to store user credential information for my website. Unfortunately, while I managed to get the website to work from my local machine, express session is empty during every request from the hosted website.
To make this easier to understand:
server:
Node.JS app
hosted website (plain HTML, javascript)
req.session always empty
local:
local server accessible by localhost.com (hosts was edited to redirect localhost.com to 127.0.0.1)
req.session has the things I set in it
The website files are identical/synced & both connect to the same server.
requests from the website are ajax with default:
$.ajaxSetup({
xhrFields: {
withCredentials: true //for server-side sessions
}
});
server app.js setup:
var express = require('express');
var expsession = require('express-session');
var config = require('./config');
var app = express();
app.set('port', process.env.PORT || 3333);
app.use(require('method-override')());
app.use(require('morgan')('dev'));
app.use(require('body-parser')({ keepExtensions: true}));
app.use(require('cookie-parser')());
app.use(expsession({
secret: 'stufffandthings',
store: new expsession.MemoryStore({reapInterval: 600000})
}));
app.use(function(req, res, next) {
console.log('From: ' + req.get('origin'));
if(config.origins.indexOf(req.get('origin')) > -1){ //if in list of allowed origins
res.header("Access-Control-Allow-Origin", req.get('origin')); //allow them in
console.log('Set access control to allow origin');
}
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, X-Requested-With, Authorization, Content-Length');
res.header('Access-Control-Allow-Credentials', true);
res.header("Cache-Control", "no-cache");
next();
});
config.origins contains my http://localhost.com:3700 & http://hostedwebsite.com:8080. Both the localhost and local website are allowed origins.
Edit:
On the hosted website, if you don't leave the page and keep doing ajax requests the session object remembers you. Huh?
app.use(express.static(path.join(__dirname, '/public')));
Had to be above the express-session middleware declaration. It's a bug with express-session module.

Categories