UNPKG

6.63 kBMarkdownView Raw
1# S3O Lambda
2
3This library makes it a lot easier & faster to secure the HTTP endpoints of AWS Lambda-based serverless applications to FT staff only.
4
5For an equivalent for [Express](https://expressjs.com/) based services, see [s3o-middleware](https://github.com/Financial-Times/s3o-middleware).
6
7## Installation
8
9```sh
10npm install --save @financial-times/s3o-lambda
11```
12
13## Usage
14
15The simplest setup consists of the following:
16
17```js
18const s3o = require('@financial-times/s3o-lambda');
19
20module.exports.handler = (event, context, callback) => {
21 s3o(event, callback).then(({ isSignedIn, username }) => {
22 if (isSignedIn) {
23 // your apps logic and eventual call of 'callback'
24 callback(null, { statusCode: 200, body: 'You are signed in.' });
25 }
26 // do not call callback if the user is isSignedIn is false
27 // it has already been called by s3o-lambda
28 });
29};
30```
31
32If you wish to use a vanity URL (e.g `runbooks.ft.com` rather than `https://115e7cvz86.execute-api.eu-west-1.amazonaws.com/prod`), you may want to customise the `X-FT-Forwarding-Host` header passed to your Lambda, or customise the [getHost](<#getHost(event)>) option.
33
34### API
35
36#### s3o(event, callback, [options])
37
38Returns a Promise which resolves to an object:
39
40- `isSignedIn`: `bool` indicates whether the user is signed in.
41- `username`: `string` | `undefined` the s3o-username of the user if it existed in a cookie.
42
43In the event that the user is not signed in the `callback` will be called to redirect the user to the correct location. This indicates the Lambda is ready to return a response to the user. The callback should not be called again in this instance, if it is it will be a no-op and produce an AWS Lambda warning.
44
45If the user has the correct cookies but validation of the cookies fails, they will receive a 401 response clearing their cookies, rather than a redirect. This is in order to prevent redirect loops if there is an issue with S3O.
46
47##### Options
48
49###### redirect
50
51This library will redirect the user to sign in using Google if not signed in, and return the user to this same page when successful.
52
53If you want to prevent the redirect behaviour, pass `{redirect: false}` as the third parameter:
54
55```js
56const s3o = require('@financial-times/s3o-lambda');
57
58module.exports.handler = (event, context, callback) => {
59 s3o(event, callback, { redirect: false }).then(({ isSignedIn }) => {
60 if (isSignedIn) {
61 callback(null, { statusCode: 200, body: 'You are signed in.' });
62 }
63 });
64};
65```
66
67Unauthorised users will receive a 401 status code. It is then up to you to handle
68redirecting the user to the S3O service in your client-side app.
69
70###### protocol
71
72Type: `string`
73Default: `https`
74
75To allow use with `http` (useful for local development), pass in `{protocol: 'http'}` as the third parameter.
76
77###### cookies
78
79Type: `object`
80
81Cookie options:
82
83- httpOnly: `boolean` Sets the `HttpOnly` flag on S3O cookies. Default `true`
84- maxAge: `string` `int` Sets the `Max-Age` flag on S3O cookies. Default: `900000`
85- secure: `boolean` Sets the `Secure` flag on S3O cookies. Default `protocol === 'https'`
86
87###### getHost(event)
88
89Type: `Function` `string`
90
91A function which returns a host to be used as a redirectURL when redirecting to S3O.
92A constant string can also be used if this is static for the given handler.
93
94In most cases you will want your Lambda handler to have a vanity URL, rather than the default execution URL.
95AWS API Gateway routes by the `Host` header, so it's difficult to retrieve the original header without setting a forwarding header. If the `Host` header is used, the user will be redirected to the orginal API Gateway URL rather than your vanity URL.
96
97Overrides are used in the following order:
98
991. A provided `getHost` function or string, see below.
1002. The `X-FT-Forwarding-Host` header. This can be used as a generic override for any upstream proxy.
1013. The `Fastly-Orig-Host` header. If using Fastly and an ['override host header'](https://docs.fastly.com/guides/basic-configuration/specifying-an-override-host) is set, the original header is propagated as `Fastly-Orig-Host`.
102
103If setting custom headers doesn't meet your requirements, it may be useful to pass a `getHost` function. e.g.
104
105````js
106getHost(event) {
107 return event.headers['Custom-Forwarded-Host-Header'];
108}
109```
110
111As a string
112
113```js
114// may wish to store this in an environment variable
115const getHost = 'https://runbooks.ft.com';
116````
117
118Passing an invalid type will result in an immediate promise rejection by `s3o-lambda`.
119
120###### getPath(event, host)
121
122Type: `Function` `string`
123
124A function which returns the URL path to be used as a redirectURL when redirecting to S3O.
125A constant string can also be used if this is static for the given handler.
126By default the path is calculated by:
127
1281. Take the `X-FT-Forwarding-Path` header if it is provided.
1292. If host is a default AWS Lambda URL - i.e. it contains amazonaws.com, take `event.path` and prepend the `stage` variable from `requestContext`.
1303. Take the value of `event.path`.
131
132In most cases the default behaviour should not need to be modified.
133
134```js
135getPath(event, host) {
136 return '/v1/some-hardcoded-path';
137}
138```
139
140Passing an invalid type will result in an immediate promise rejection by `s3o-lambda`.
141
142###### getS3oClientName(event)
143
144Type: `Function` `string`
145
146At the time of writing, S3O tokens are irrevocable. To ensure that leaked s3o tokens cannot be re-used on other services an identifier must be passed to the S3O `/authorise` endpoint as a `host` query parameter.
147
148The default behaviour is to take the output of [getHost](<#getHost(event)>).
149This can be customised by passing a `getS3oClientName` function which takes the lambda `event` as an argument.
150A constant string can also be used if this is static for the given handler.
151
152```js
153// function
154module.exports.handler = (event, context, callback) => {
155 s3o(event, callback, {
156 getIdentifier(event) {
157 return event.headers.host + 'my-lambda';
158 },
159 }).then(({ isSignedIn }) => {
160 if (isSignedIn) {
161 callback(null, { statusCode: 200, body: 'You are signed in.' });
162 }
163 });
164};
165```
166
167```js
168// string
169module.exports.handler = (event, context, callback) => {
170 s3o(event, callback, { getS3oClientName: 'my-lambda-function' }).then(
171 ({ isSignedIn }) => {
172 if (isSignedIn) {
173 callback(null, { statusCode: 200, body: 'You are signed in.' });
174 }
175 }
176 );
177};
178```
179
180Passing an invalid type will result in an immediate promise rejection by `s3o-lambda`.