@financial-times/s3o-lambda
TypeScript icon, indicating that this package has built-in type declarations

2.0.3 • Public • Published

S3O Lambda

This library makes it a lot easier & faster to secure the HTTP endpoints of AWS Lambda-based serverless applications to FT staff only.

For an equivalent for Express based services, see s3o-middleware.

Note: v2 requires the lambda to be running on node 8 or greater. If your lambda uses node 6 then use v1.x.x

Installation

npm install --save @financial-times/s3o-lambda

Usage

The simplest setup consists of the following:

const s3o = require('@financial-times/s3o-lambda');

module.exports.handler = (event, context, callback) => {
    s3o(event, callback).then(({ isSignedIn, username }) => {
        if (isSignedIn) {
            // your apps logic and eventual call of 'callback'
            callback(null, { statusCode: 200, body: 'You are signed in.' });
        }
        // do not call callback if the user is isSignedIn is false
        // it has already been called by s3o-lambda
    });
};

If 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 option.

API

s3o(event, callback, [options])

Returns a Promise which resolves to an object:

  • isSignedIn: bool indicates whether the user is signed in.
  • username: string | undefined the s3o-username of the user if it existed in a cookie.

In 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.

If 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.

Options
redirect

This library will redirect the user to sign in using Google if not signed in, and return the user to this same page when successful.

If you want to prevent the redirect behaviour, pass {redirect: false} as the third parameter:

const s3o = require('@financial-times/s3o-lambda');

module.exports.handler = (event, context, callback) => {
    s3o(event, callback, { redirect: false }).then(({ isSignedIn }) => {
        if (isSignedIn) {
            callback(null, { statusCode: 200, body: 'You are signed in.' });
        }
    });
};

Unauthorised users will receive a 401 status code. It is then up to you to handle redirecting the user to the S3O service in your client-side app.

protocol

Type: string Default: https

To allow use with http (useful for local development), pass in {protocol: 'http'} as the third parameter.

cookies

Type: object

Cookie options:

  • httpOnly: boolean Sets the HttpOnly flag on S3O cookies. Default true
  • maxAge: string int Sets the Max-Age flag on S3O cookies. Default: 900000
  • secure: boolean Sets the Secure flag on S3O cookies. Default protocol === 'https'
getHost(event)

Type: Function string

A function which returns a host to be used as a redirectURL when redirecting to S3O. A constant string can also be used if this is static for the given handler.

In most cases you will want your Lambda handler to have a vanity URL, rather than the default execution URL. AWS 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.

Overrides are used in the following order:

  1. A provided getHost function or string, see below.
  2. The X-FT-Forwarding-Host header. This can be used as a generic override for any upstream proxy.
  3. The Fastly-Orig-Host header. If using Fastly and an 'override host header' is set, the original header is propagated as Fastly-Orig-Host.

If setting custom headers doesn't meet your requirements, it may be useful to pass a getHost function. e.g.

getHost(event) {
	return event.headers['Custom-Forwarded-Host-Header'];
}
```

As a string

```js
// may wish to store this in an environment variable
const getHost = 'https://runbooks.ft.com';

Passing an invalid type will result in an immediate promise rejection by s3o-lambda.

getPath(event, host)

Type: Function string

A function which returns the URL path to be used as a redirectURL when redirecting to S3O. A constant string can also be used if this is static for the given handler. By default the path is calculated by:

  1. Take the X-FT-Forwarding-Path header if it is provided.
  2. If host is a default AWS Lambda URL - i.e. it contains amazonaws.com, take event.path and prepend the stage variable from requestContext.
  3. Take the value of event.path.

In most cases the default behaviour should not need to be modified.

getPath(event, host) {
	return '/v1/some-hardcoded-path';
}

Passing an invalid type will result in an immediate promise rejection by s3o-lambda.

getS3oClientName(event)

Type: Function string

At 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.

The default behaviour is to take the output of getHost. This can be customised by passing a getS3oClientName function which takes the lambda event as an argument. A constant string can also be used if this is static for the given handler.

// function
module.exports.handler = (event, context, callback) => {
    s3o(event, callback, {
        getIdentifier(event) {
            return event.headers.host + 'my-lambda';
        },
    }).then(({ isSignedIn }) => {
        if (isSignedIn) {
            callback(null, { statusCode: 200, body: 'You are signed in.' });
        }
    });
};
// string
module.exports.handler = (event, context, callback) => {
    s3o(event, callback, { getS3oClientName: 'my-lambda-function' }).then(
        ({ isSignedIn }) => {
            if (isSignedIn) {
                callback(null, { statusCode: 200, body: 'You are signed in.' });
            }
        }
    );
};

Passing an invalid type will result in an immediate promise rejection by s3o-lambda.

Readme

Keywords

Package Sidebar

Install

npm i @financial-times/s3o-lambda

Weekly Downloads

2

Version

2.0.3

License

ISC

Unpacked Size

405 kB

Total Files

23

Last publish

Collaborators

  • robertboulton
  • seraph2000
  • hamza.samih
  • notlee
  • emmalewis
  • aendra
  • the-ft
  • rowanmanning
  • chee
  • alexwilson