47

I have a REST api created with the restify module and I want to allow cross-origin resource sharing. What is the best way to do it?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Kim
  • 4,593
  • 5
  • 21
  • 18

14 Answers14

66

You have to set the server up to set cross origin headers. Not sure if there is a built in use function or not, so I wrote my own.

server.use(
  function crossOrigin(req,res,next){
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    return next();
  }
);

I found this from this tutorial. http://backbonetutorials.com/nodejs-restify-mongodb-mongoose/

Stephen Reid
  • 701
  • 6
  • 4
64

The latest version of Restify provides a plugin to handle CORS.

So you can now use it like this:

server.use(restify.CORS({

  // Defaults to ['*'].
  origins: ['https://foo.com', 'http://bar.com', 'http://baz.com:8081'], 

  // Defaults to false.
  credentials: true,

  // Sets expose-headers.
  headers: ['x-foo']   

}));
Slava Fomin II
  • 26,865
  • 29
  • 124
  • 202
  • 3
    which version of restify? (you said "last version of restify...") – Cheeso Jul 31 '13 at 04:03
  • 1
    @Jean-MichelTrayaud: this doesn't work for me... I'm getting *Origin http://192.168.2.124 is not allowed by Access-Control-Allow-Origin*. Any help will be apreciated :) – Daniele Vrut Oct 30 '13 at 14:55
  • think we need more information... GET or POST in first time (POST is really a nightmare with CORS) – Jean-Michel Trayaud Nov 04 '13 at 11:54
  • Testing against Restify 3.0.3, using `restify.CORS()` by itself was sufficient. No need for `restify.fullResponse()`, but in the request, you need to specify the `Origin` header. See related code comment in [cors.js](https://github.com/restify/node-restify/blob/master/lib/plugins/cors.js). – Mark Berryman Sep 10 '15 at 16:10
  • This plugin has a strange behavior. If the origin matches one of the array, it will return the matching origin in the response header, which is expected. If it doesn't match however, it will return a wildcard. It will still fail if you make a credentialized cors request, because then the origin must not be *. But why return * anyway? – Maciej Krawczyk Jul 11 '17 at 05:45
  • i am using restify 5.0.1, and can't find the solution regarding CORS – Ahmer Saeed Aug 16 '17 at 11:41
  • Note that this plugin has been removed in favour of [a middleware solution](https://github.com/Tabcorp/restify-cors-middleware) ([source](https://github.com/restify/node-restify/issues/1091#issuecomment-271403137)) – Christallkeks Sep 05 '19 at 14:34
14

This works for me:

var restify = require('restify');

var server = restify.createServer();

server.use(restify.CORS());

server.opts(/.*/, function (req,res,next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", req.header("Access-Control-Request-Method"));
    res.header("Access-Control-Allow-Headers", req.header("Access-Control-Request-Headers"));
    res.send(200);
    return next();
});

server.get('/test', function (req,res,next) {

    res.send({
        status: "ok"
    });
    return next();
});

server.listen(3000, function () {
    console.log('%s listening at %s', server.name, server.url);
});
Cyrusmith
  • 747
  • 1
  • 9
  • 17
  • For some reason, the other answers did not work for me. Yours did. I wonder if it has something to do with changes made to latest versions of restify. – guagay_wk Nov 12 '15 at 05:11
10

This is what worked for me:

function unknownMethodHandler(req, res) {
  if (req.method.toLowerCase() === 'options') {
      console.log('received an options method request');
    var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With']; // added Origin & X-Requested-With

    if (res.methods.indexOf('OPTIONS') === -1) res.methods.push('OPTIONS');

    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
    res.header('Access-Control-Allow-Methods', res.methods.join(', '));
    res.header('Access-Control-Allow-Origin', req.headers.origin);

    return res.send(204);
  }
  else
    return res.send(new restify.MethodNotAllowedError());
}

server.on('MethodNotAllowed', unknownMethodHandler);

I this code was taken from https://github.com/mcavage/node-restify/issues/284

Pavel Nikolov
  • 9,401
  • 5
  • 43
  • 55
  • This worked for me, but I also needed to add `server.use(restify.fullResponse());` prior to the call to `server.on(...)`. – Cheeso Jul 31 '13 at 04:36
  • This almost worked for me. I had to use `server.opts({path: '/customers', version: '0.0.1'}, unknownMethodHandler);`. With `on`, the method just wasn't called. – J.P. Feb 27 '14 at 13:37
  • This avoids the 404 "Method not allowed" response from restify for OPTIONS preflight requests. The CORS cross-origin problem must be handled separately--see "crossOrigin function above for a fix that problem. – terrymorse May 19 '18 at 19:14
6

CORS Plugin is deprecated in favor of https://github.com/Tabcorp/restify-cors-middleware. (Source: https://github.com/restify/node-restify/issues/1091.)

Below is a sample code regarding how to use

const corsMiddleware = require('restify-cors-middleware')

const cors = corsMiddleware({
  preflightMaxAge: 5, //Optional
  origins: ['http://api.myapp.com', 'http://web.myapp.com'],
  allowHeaders: ['API-Token'],
  exposeHeaders: ['API-Token-Expiry']
})

server.pre(cors.preflight)
server.use(cors.actual)
techgyani
  • 535
  • 8
  • 24
5

If anyone comes across this as of Feb 2018 there seems to be a bug that's been introduced, I couldn't get the restify-cors-middleware to work.

I'm using this work around for now:

server.pre((req, res, next) => {
   res.header("Access-Control-Allow-Origin", "*");
   next();
});
Giuseppe
  • 288
  • 2
  • 12
  • This is the only solution which works right now in 07/2021, everything else is obsolete or has a bug, also the "new" middleware. restify is a mess, I recommending anyone new to NOT use it. – Sam Jul 26 '21 at 13:49
  • So it's not just me who's had trouble with the plugins! Phew. – Prachi Aug 30 '21 at 17:20
  • Btw, when I use this, I get 404s on my endpoints. :( – Prachi Aug 30 '21 at 20:31
4

To enable CORS for basic authentication I did the following. It did not work until the .pre methods were used instead of the .use methods

server.pre(restify.CORS({
  origins: ['https://www.allowedip.com'],  // defaults to ['*']
  credentials: true,
  headers: ['X-Requested-With', 'Authorization']
}));
server.pre(restify.fullResponse());

function unknownMethodHandler(req, res) {
    if (req.method.toLowerCase() === 'options') {
      var allowHeaders = ['Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With', 'Authorization']; // added Origin & X-Requested-With & **Authorization**

      if (res.methods.indexOf('OPTIONS') === -1) res.methods.push('OPTIONS');

      res.header('Access-Control-Allow-Credentials', true);
      res.header('Access-Control-Allow-Headers', allowHeaders.join(', '));
      res.header('Access-Control-Allow-Methods', res.methods.join(', '));
      res.header('Access-Control-Allow-Origin', req.headers.origin);

      return res.send(200);
   } else {
      return res.send(new restify.MethodNotAllowedError());
   }
}

server.on('MethodNotAllowed', unknownMethodHandler);
respectTheCode
  • 42,348
  • 18
  • 73
  • 86
Mel
  • 51
  • 3
3

I do it like this on my restify base app:

//setup cors
restify.CORS.ALLOW_HEADERS.push('accept');
restify.CORS.ALLOW_HEADERS.push('sid');
restify.CORS.ALLOW_HEADERS.push('lang');
restify.CORS.ALLOW_HEADERS.push('origin');
restify.CORS.ALLOW_HEADERS.push('withcredentials');
restify.CORS.ALLOW_HEADERS.push('x-requested-with');
server.use(restify.CORS());

you need to use restify.CORS.ALLOW_HEADERS.push method to push the header u want into restify first, then using the CORS middleware to boot the CORS function.

Lyman Lai
  • 191
  • 1
  • 4
  • 1
    I'm using Restify v2.8.3, and some of these headers are already enabled by default. Check out the defaults in `./node_modules/restify/lib/plugins/cors.js`. – Jeff Fairley Dec 05 '14 at 21:33
3

MOST OF THE PREVIOUS ANSWERS ARE FROM 2013 AND USE DEPRECATED EXAMPLES! The solution (in 2017 at least) is as follows:

npm install restify-cors-middleware

Then in your server javascript file:

var corsMiddleware = require('restify-cors-middleware');

var cors = corsMiddleware({
  preflightMaxAge: 5,
  origins: ['*']
});

var server = restify.createServer();

server.pre(cors.preflight);
server.use(cors.actual);

And add whatever additional other options work for you. My use case was creating a localhost proxy to get around browser CORS issues during devolopment. FYI I am using restify as my server, but then my POST from the server (and to the server) is with Axios. My preference there.

npm listing for restify-cors-middleware

MattC
  • 5,874
  • 1
  • 47
  • 40
2

This sufficed in my case:

var server = restify.createServer();
server.use(restify.fullResponse());
server.get('/foo',  respond(req, res, next) {
   res.send('bar');
   next();
});

It wasn't necessary to server.use(restify.CORS()); Also, it appears server.use() calls must precede server.get() calls in order to work.

Julian A.
  • 10,928
  • 16
  • 67
  • 107
1

This worked for me with restify 7

server.pre((req, res, next) => {

    res.header('Access-Control-Allow-Origin', req.header('origin'));
    res.header('Access-Control-Allow-Headers', req.header('Access-Control-Request-Headers'));
    res.header('Access-Control-Allow-Credentials', 'true');
    // other headers go here..

    if(req.method === 'OPTIONS') // if is preflight(OPTIONS) then response status 204(NO CONTENT)
        return res.send(204);

    next();

});
vedsmith92
  • 579
  • 3
  • 5
0

I am using Restify 7.2.3 version and this code worked for me very well. You need to install the restify-cors-middleware plugin.

const corsMiddleware = require('restify-cors-middleware')

const cors = corsMiddleware({
    preflightMaxAge: 5, //Optional
    origins: ['http://ronnie.botsnbytes.com', 'http://web.myapp.com'],
    allowHeaders: ['API-Token'],
    exposeHeaders: ['API-Token-Expiry']
})

server.pre(cors.preflight)
server.use(cors.actual)
-1
   const cors = require('cors');


   const server = restify.createServer();

   server.use(cors());

This worked for me

-1
const restify = require('restify');
const corsMiddleware = require('restify-cors-middleware');

const cors = corsMiddleware({
  origins: ['*']
});

const server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);

server.get('/api/products', (request, response) => {
  response.json({ message: 'hello REST API' });
});

server.listen(3000, () => console.info(`port 3000`));

... is one brute-force solution, though you should be very careful doing that.

James Shapiro
  • 4,805
  • 3
  • 31
  • 46