Browse Source

run HTTP behind HTTPS BrowserSync proxy and have that work

pull/2/head
Rob Colbert 2 years ago
parent
commit
3d11549f1c
  1. 80
      docs/iframe-embeds.md
  2. 7
      gulpfile.js
  3. 10
      lib/site-platform.js

80
docs/iframe-embeds.md

@ -0,0 +1,80 @@
# Enabling SSL Through BrowserSync and Gulp To Support <iframe>
It is possible to run a DTP application server with SSL features, but this is not commonly done. Instead, a forward-facing proxy (Nginx) is used to terminate SSL requests, and HTTP requests are then used to communicate with the DTP application servers.
There is a problem with this, though. In order to be able to embed content from this site into other sites using an <iframe> while allowing members to be logged in requires a lot of magic settings in areas of the code few people understand.
You will configure BrowserSync and [express-session](https://github.com/expressjs/session) with options that rely on each other to work properly. BrowserSync needs to "fake" some headers that would normally be created by Nginx, and BrowserSync needs to be told to allow the Secure attribute to pass through during login responses.
The project is already configured this way. This document describes *why* it is configured this way, and what the configuration accomplishes.
**NOTE**: This document refers to `dtp-base` and the DTP Base project's settings. You will need to adapt those values to your project, your domain, and your settings.
## Generate the SSL Certificate for Dev
You have to generate the SSL certificate for use in dev as follows:
```sh
cd ssl
./mkcert
```
BrowserSync is configured to load these self-signed certs and use them to provide HTTPS service for the application. In production, this is done by Nginx. In both cases, SSL is terminated at the proxy, and HTTP is used to communicate to the back-end application server.
This requires the following options to be passed to BrowserSync's init:
```js
{
proxy: {
target: 'http://dev.base.digitaltelepresence.com:3010',
ws: true,
reqHeaders: {
'X-Forwarded-For': '127.0.0.1',
'X-Forwarded-Proto': 'https',
},
cookies: { stripDomain: false },
},
host: 'dev.base.digitaltelepresence.com',
open: 'external',
https: {
key: path.join(__dirname, 'ssl', 'dtp-base.key'),
cert: path.join(__dirname, 'ssl', 'dtp-base.crt'),
},
port: 3380,
cors: true,
}
```
We have to set `X-Forwarded-For` and `X-Forwarded-Proto` so that [express-session](https://github.com/expressjs/session) will trust the request and set a cookie during login. And that's just the BrowserSync requirements. There's more.
And, if you don't set `cookies: { stripDomain: false }` then BrowserSync will rip the `Secure` attribute right off your cookie on it's way through. Most browsers will then reject the cookie for having cross-site options and being insecure.
If you can't authenticate and log in, this is why.
## express-session
[express-session](https://github.com/expressjs/session) has a host of requirements for enabling secure cross-site session cookies. These are cookies with `sameSite` set to `none` and also with `secure` set.
To do this, you have to set the `proxy` option to true, the `cookie.secure` option to true, and the `cookie.sameSite` option to `"none"`. All of these settings are important for getting the cookie generated:
```js
module.sessionConfig = {
proxy: IS_PRODUCTION || (process.env.HTTP_SESSION_TRUST_PROXY === 'enabled'),
cookie: {
domain: 'dev.base.digitaltelepresence.com',
httpOnly: true,
secure: process.env.HTTP_COOKIE_SECURE === 'enabled',
sameSite: process.env.HTTP_COOKIE_SAMESITE || false,
},
};
```
The domain has to match. The cookie has to be `httpOnly`. It has to be secure. It has to be cross-site. This is then what enables other sites to "embed" content from this site and allow the member to be logged in and do things like use chat.
If you can't embed content from your site into other sites with a logged-in user, this is most likely why. You need to configure Nginx to forward some headers to the HTTP application server that let `express-session` know it's okay to send a Secure cross-site cookie back, so we also configure BrowserSync to simluate that behavior that in dev.
## References
- [express-session](https://github.com/expressjs/session)
- [HTTP headers and Classic Load Balancers](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html)
- [unable to use secure cookies #281](https://github.com/expressjs/session/issues/281)
- [Setting the cookie domain when using the proxy option #737](https://github.com/BrowserSync/browser-sync/issues/737)

7
gulpfile.js

@ -22,8 +22,13 @@ function util_start_browsersync ( ) {
return new Promise((resolve, reject) => {
browserSync.init({
proxy: {
target: 'https://dev.base.digitaltelepresence.com:3410',
target: 'http://dev.base.digitaltelepresence.com:3010',
ws: true,
reqHeaders: {
'X-Forwarded-For': '127.0.0.1',
'X-Forwarded-Proto': 'https',
},
cookies: { stripDomain: false },
},
host: 'dev.base.digitaltelepresence.com',
open: 'external',

10
lib/site-platform.js

@ -298,7 +298,7 @@ module.exports.startWebServer = async (dtp) => {
name: `dtp:${process.env.DTP_SITE_DOMAIN_KEY}.${process.env.NODE_ENV}`,
secret: process.env.HTTP_SESSION_SECRET,
resave: true,
proxy: IS_PRODUCTION,
proxy: IS_PRODUCTION || (process.env.HTTP_SESSION_TRUST_PROXY === 'enabled'),
saveUninitialized: true,
cookie: {
domain: process.env.DTP_SITE_DOMAIN_KEY,
@ -308,7 +308,7 @@ module.exports.startWebServer = async (dtp) => {
sameSite: process.env.HTTP_COOKIE_SAMESITE || false,
expires: SESSION_DURATION,
},
store: null,
store: sessionStore,
};
module.log.info('configuring session handler', {
domain: module.sessionConfig.cookie.domain,
@ -317,10 +317,10 @@ module.exports.startWebServer = async (dtp) => {
sameSite: module.sessionConfig.cookie.sameSite,
expires: module.sessionConfig.cookie.expires,
});
module.sessionConfig.store = sessionStore;
if (IS_PRODUCTION && module.sessionConfig.cookie.secure) {
if (module.sessionConfig.proxy) {
module.log.info('session will be trusting first proxy');
module.app.set('trust proxy', 1);
module.app.set('trust proxy', true);
module.sessionConfig.cookie.secure = true;
}
module.app.use(session(module.sessionConfig));

Loading…
Cancel
Save