Search code examples
node.jscorsbotframeworkweb-chat

Bot Framework Webchat unable to get token from Node.js restify server (on Azure): CORS policy: No 'Access-Control-Allow-Origin' header is present


To start the Bot Framework webchat client, I need to 'get' a token from a restify server running in Azure. The server fetches the token (using my secret) from https://webchat.botframework.com/api/tokens. The last part works fine. The first part didn't. I did not manage to get the webchat client to accept the response from the restify server. Offline (localhost) works fine. When the server is running online (Node in Azure) I get:

Access to fetch at 'https://mybot.azurewebsites.net/api/token' from origin 'https://mydomainname.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

In the dev tool of chrome I can see that with restify server running on local host, I get an access-control-allow-origin and an access-control-expose-header. When running on Node (in Azure) I only get access-control-expose-header.

What did I already try (without a good result):

  1. Implement cors middleware for restify server
  2. Use Express in stead of restify
  3. add headers manually to the response: res.send(token, { 'Access-Control-Allow-Origin': '*' })
  4. specify the domain name in the (trusted) origins list of Cors middelware
    1. [the solution] add the domain name running the calling javascript in the list with approved origins in the azure app service running the restify service.

My current code (with the Cors middleware)

Restify server

const fetch = require('node-fetch');
const restify = require('restify');
const path = require('path');
const corsMiddleware = require('restify-cors-middleware');

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

// Create HTTP server and Cors
let server = restify.createServer();
server.use(cors.actual);
server.listen(process.env.port || process.env.PORT || 3978, function() {
    console.log(`\n${ server.name } listening to ${ server.url }.`);
    console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator.`);
});

// Listen for bot requests.
server.post('/api/messages', (req, res) => {
    adapter.processActivity(req, res, async (context) => {
        await bot.run(context);
    });
});

// Listen for token requests.
server.get('/api/token',
    async function(req, res) {
        const result = await fetch('https://webchat.botframework.com/api/tokens', {
            method: 'GET',
            headers: {
                Authorization: `Bearer ${ process.env.directLineSecret }`
            }
        });
        const token = await result.json();
        console.log(token);
        res.send(token);
    });

The webchat client

In this code snippet, the client is talking to a server running on local host. This works. As soon as we talk to a server hosted on Azure, it doesn't work anymore (due to cors it seems)

(async function () {
  const res = await fetch('http://localhost:3978/api/token', { method: 'GET' });
  const webChatToken = await res.json();

  window.WebChat.renderWebChat({
    directLine: window.WebChat.createDirectLine({ token: webChatToken })
  }, document.getElementById('webchat'));

  document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));

Someone any thoughts on how to fix this?


Solution

  • Had me searching for a day and trying lots of options. The solution was in Azure App Service (Node) CORS origins won't work no matter where I add them

    You have to add the calling domain in the list of approved origins in the CORS menu of the appservice running your restify service. Not sure if this makes sense, but it helped.