summaryrefslogtreecommitdiff
path: root/memos/WM-029.txt
blob: e78a38708bc5546bd5ede251dbbb477f5112df81 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
Document: WM-029                                                 P. Webb
Category: Tutorial                                            2018.02.10

                    Using nginx and express-session

Abstract

   PSA for frustrated Internet searchers

Body

   When pushing Socii[1] to production, I ran into a couple of problems
   and I'm sharing them on my blog for you (learn from my mistakes!) and
   me (external memory source). This post will go over how I dealt with
   secure sessions not working out of the box with HTTPS.

   Let's start with some code. I'm using Feathers with Express but this
   code will still work sans Feathers:

   ```javascript
   const app = express(feathers())
     // above removed for brevity

     // Initialize session and restore auth state
     .use(session({
       cookie: {
         httpOnly: process.env.NODE_ENV !== "development",
         path: "/",
         maxAge: 1000 * 60 * 60 * 24 * 7, // 1 week
         secure: process.env.NODE_ENV !== "development"
       },
       proxy: process.env.NODE_ENV !== "development",
       resave: false,
       rolling: true,
       saveUninitialized: true,
       secret: secret,   // this should be an environment variable
       store: store,     // your session store of choice
     }))
   ;
   ```

   The `process.env.NODE_ENV !== "development"` is a clever shortcut I
   found while troubleshooting this issue. If `process.env.NODE_ENV`
   does not equal `development`, the result will be true in a production
   environment. In a development environment, the result would be false.
   This is assuming of course, that your development script sets the
   environment. Something like this in your `package.json`:

   ```json
   {
     …above removed for brevity

     "scripts": {
       "build": "npm run clean && npm install && npm run build-server",
       "build-server": "babel -d build server",
       "clean": "rm -rf build package-lock.json && mkdir build",
       "deploy": "vagrant push",
       "dev": "NODE_ENV=development nodemon server/index.js --ignore 'public/' --exec babel-node --presets env,stage-2",
       "sass": "sass --watch sass:public/css --style compressed",
       "start": "npm run build && NODE_ENV=production node build/index.js",
       "test": "echo \"Error: no test specified\" && exit 1"
     }
   }
   ```

   The scripts to pay attention are `dev` and `start`. You can see that
   I set the node environment before running my app. And there you have
   it, I hope you've found this post helpful!

   Going back to the `express-session` code above, I list what most of
   the parameters mean:

   1. proxy
      Trust the reverse proxy when setting secure cookies (via the
      "X-Forwarded-Proto" header). The default value is undefined.

      - `true` The "X-Forwarded-Proto" header will be used.
      - `false` All headers are ignored and the connection is considered
        secure only if there is a direct TLS/SSL connection.
      - `undefined` Uses the "trust proxy" setting from express

   2. resave

      Forces the session to be saved back to the session store, even if
      the session was never modified during the request.

   3. rolling

      Force a session identifier cookie to be set on every response. The
      expiration is reset to the original maxAge, resetting the
      expiration countdown.

      The default value is false.

      *Note* When this option is set to `true` but the
      `saveUninitialized` option is set to `false`, the cookie will not
      be set on a response with an uninitialized session.

   4. saveUninitialized

      Forces a session that is "uninitialized" to be saved to the store.
      A session is uninitialized when it is new but not modified.

   5. httpOnly

      Ensures the cookie is sent only over HTTP(S), not client
      JavaScript, helping to protect against cross-site
      scripting attacks.

   6. secure

      Ensures the browser only sends the cookie over HTTPS.

   Hope this helps! 🕸

References

   [1] <https://hub.socii.network>