Requirements:
npm i @byu-oit-sdk/session-express
Use this module to facilitate session authentication, used primarily in conjunction with the @byu-oit-sdk/express package.
The only parameter passed into SessionMiddleware
(see the example below) is an object where the following options can be set:
Option | Type | Default | Description |
---|---|---|---|
store | SessionStore | Stored in memory | The store object that will be used to store and retrieve session information |
name | string | 'sessionId' | The name of the cookie used to store the session Id in the browser storage |
maxAge | number | 1200 | The maximum age of the session, in seconds. |
None of the options are required to be overridden for testing, but store
must be overridden for production use.
Register the return value of SessionMiddleware as an express middleware:
import env from 'env-var'
import { LoggerMiddleware } from '@byu-oit/express-logger'
import { AuthorizationCodeFlow } from '@byu-oit-sdk/express'
import express, { type Response } from 'express'
import { SessionMiddleware } from '@byu-oit-sdk/session-express'
import type { Request } from 'express-serve-static-core'
import { createDecoder } from 'fast-jwt'
import { DynamoSessionStore } from '@byu-oit-sdk/session-dynamo'
import { DynamoDBClient } from '@aws-sdk/client-dynamodb'
declare module '@byu-oit-sdk/express' {
interface UserInfo {
/**
* Declare your user info object properties here
*/
}
}
export const app = express()
const secret = env.get('BYU_OIT_SIGNING_SECRET').required().asString()
const isProduction = env.get('NODE_ENV').default('development').asEnum(['production', 'development']) === 'production'
let store
if (isProduction) {
const client = new DynamoDBClient({
region: env.get('AWS_REGION').required().asString(),
endpoint: 'http://localhost:8000'
})
store = new DynamoSessionStore({ client, tableName: 'sessions' })
}
/**
* Must register the @byu-oit-sdk/session-express middleware. You must pass in a session storage option for production environments.
* Using the default in-memory storage is highly discouraged because it will cause memory leaks.
*/
const sessionMiddleware = await SessionMiddleware({ store })
app.use(sessionMiddleware)
/**
* Attach the logger to the express instance
*/
app.use(LoggerMiddleware())
/* Initialize jwt decoder for user info callback */
const decode = createDecoder()
/**
* Attach the auth middleware we're using
*/
AuthorizationCodeFlow(app, {
/**
* A user info callback function can be supplied to implement a custom way to return the user info data.
* the default behavior is to decode the access token returned from the oauth provider token endpoint.
* The context of the `userInfoCallback` function is bound to the ExpressAuthorizationCodeProvider instance.
*/
userInfoCallback (token) {
if (typeof token.additional.id_token !== 'string') {
/** At BYU OIT the `id_token` property exists in the token response body. We can access it on the `additional` property on the token object. */
throw Error('Missing or mal-formatted ID token in response from token endpoint. Did you set the right scopes?')
}
/** Decode the `id_token` property, which should return the user info object. */
return decode(token.additional.id_token)
}
})
/**
* To require authentication for a route, just specify the authenticate function on the request object in the onRequest hook.
*/
app.get('/auth/user', (req: Request, res: Response) => {
res.contentType('application/json').send(req.session.user)
})
app.use((err, req, res, _next) => {
console.error(err.stack)
res.status(500).send('Something broke!')
})