DynamoDB-based session store for express-session, using the AWS SDK for JS v3, offering configurability for cost, performance, and reliability not found in other DynamoDB session stores.
DynamoDB is an excellent choice for session stores because it is a fully managed service that is highly available, durable, and can scale automatically (to nearly unlimited levels) to meet demand. DynamoDB reads will typically return in 1-3 ms if capacity is set correctly and the caller is located in the same region as the Table
.
The package is available on npm as @pwrdrvr/dynamodb-session-store
npm i @pwrdrvr/dynamodb-session-store
import { DynamoDBStore } from '@pwrdrvr/dynamodb-session-store';
The following IAM permissions are required for the DynamoDB Table:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowDynamoDBAccess",
"Effect": "Allow",
"Action": [
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:UpdateItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/dynamodb-session-store-test"
}
]
}
See the examples directory for more examples
import express from 'express';
import session from 'express-session';
import { DynamoDBStore } from '@pwrdrvr/dynamodb-session-store';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
const app = express();
const dynamoDBClient = new DynamoDBClient({});
app.use(
session({
store: new DynamoDBStore({
tableName: 'some-table',
dynamoDBClient,
touchAfter: 60 * 60, // 60 minutes in seconds
}),
secret: 'yeah-change-this',
cookie: {
maxAge: 14 * 24 * 60 * 60 * 1000, // 14 days in milliseconds
},
resave: false,
saveUninitialized: false,
}),
);
app.get('/login', (req, res) => {
console.log(`Session ID: ${req.session?.id}`);
req.session.user = 'test';
res.send('Logged in');
});
app.get('/*', (req, res) => {
res.status(200).send('Hello world');
});
app.listen(Number.parseInt(PORT, 10), () => {
console.log(`Example app listening on port ${port}`);
});
The following field types are fully supported by the DynamoDBStore
:
string
number
boolean
object
The following field types are partially supported by the DynamoDBStore
:
Date
Date
object since it is not known which fields were originally Date
objects vs date stringsDate
objects to strings as well and also does not support automatic conversion back to Date
objects since it serializes using JSON.stringify() and JSON.parse()After installing the package review the API Documentation for detailed on each configuration option.
Strongly Consistent Reads
.touch()
calls from express-session
express-session
would have made that a configurable option for every session store, but alas, it was rejected in favor of implementing the same thing 15+ timesexpires
fieldDisclaimer: perform your own pricing calculation, monitor your costs during and after initial launch, and setup cost alerts to avoid unexpected charges.
Source: ./examples/express.ts
aws dynamodb create-table --table-name dynamodb-session-store-test --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST
dynamodb-session-store-test
id
expires
aws dynamodb update-time-to-live --table-name dynamodb-session-store-test --time-to-live-specification "Enabled=true, AttributeName=expires"
npm run example:express
TABLE_NAME=my-table-name npm run example:express
http://localhost:3001/login
in a browserSource: ./examples/cross-account.ts
This example has the DynamoDB in one account and the express app using an IAM role from another account to access the DynamoDB Table using temporary credentials from an STS AssumeRole call (neatly encapsulated by the AWS SDK for JS v3).
This example is more involved than the others as it requires setting up an IAM role that can be assumed by the app account.
Instructions for Cross-Account DynamoDB Table Example
Source: ./examples/other.ts
aws dynamodb create-table --table-name connect-dynamodb-test --attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST
dynamodb-session-store-test
id
expires
aws dynamodb update-time-to-live --table-name connect-dynamodb-test --time-to-live-specification "Enabled=true, AttributeName=expires"
npm run example:express
TABLE_NAME=my-table-name npm run example:other
http://localhost:3001/login
in a browser@pwrdrvr/dynamodb-session-store
scan
functionality that can make the DB completely unavailable if accidentally invokedtouch
calls that update the TTL on every read, which can be very expensive (configurable)sess
field to a Map
on DynamoDB for easier querying vs dynamodb-connect
which serializes to a String
dynamodb-connect
is easy, just set the prefix
, hashKey
, and table
fields to the same values as dynamodb-connect
- the get
function will automatically deserialize the JSON sess
field if foundexpress-session
are provided@pwrdrvr/dynamodb-session-store
DB Record{
"id": "123",
"sess": {
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
},
"name": "paul"
},
"expires": 1621968000
}
dynamodb-connect
DB Record{
"id": "123",
"sess": "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"name\":\"paul\"}",
"expires": 1621968000
}
Generated using TypeDoc