Skip to content

Instantly share code, notes, and snippets.

@ShaharIlany
Last active April 12, 2023 18:53
Show Gist options
  • Save ShaharIlany/b0be76dae7caeace4cf23fb33d02e182 to your computer and use it in GitHub Desktop.
Save ShaharIlany/b0be76dae7caeace4cf23fb33d02e182 to your computer and use it in GitHub Desktop.
Blitz.js Auth Session Config for Redis
import { AuthServerPlugin, simpleRolesIsAuthorized } from "@blitzjs/auth"
import { setupBlitzServer } from "@blitzjs/next"
import { authConfig } from "./blitz-client"
import SessionStorage from "@/auth/SessionStorageRedis"
export const { api, gSSP } = setupBlitzServer({
plugins: [
AuthServerPlugin({
...authConfig,
storage: SessionStorage,
}),
],
})
import { SessionConfigMethods, SessionModel } from "@blitzjs/auth"
import { loadEnvConfig } from "@next/env"
import IoRedis from "ioredis"
const notEmpty = <TValue>(value: TValue | null | undefined): value is TValue =>
!(value === null || value === undefined)
const { REDIS_HOST, REDIS_PORT, REDIS_USER, REDIS_PASSWORD } = loadEnvConfig(
process.cwd()
).combinedEnv
const differenceInSeconds = (left: Date, right: Date) =>
Math.floor((left.getTime() - right.getTime()) / 1000)
/**
* Global is used here to ensure the connection
* is cached across hot-reloads in development
*
* see https://github.com/vercel/next.js/discussions/12229#discussioncomment-83372
*/
let redisClient: Record<string, IoRedis> = global.redisClient
if (!redisClient) redisClient = global.redisClient = {}
const getRedisClient = () => {
if (!redisClient.authClient) {
redisClient.authClient = new IoRedis({
port: Number(REDIS_PORT!),
host: REDIS_HOST!,
username: REDIS_USER!,
password: REDIS_PASSWORD!,
tls: {},
})
}
return redisClient.authClient
}
const getSession: SessionConfigMethods["getSession"] = async (handle: string) => {
try {
const client = getRedisClient()
const session = await client.get(`session:${handle}`)
if (!session) {
return null
}
const parsedSession = JSON.parse(session) as SessionModel
if (parsedSession.expiresAt) {
parsedSession.expiresAt = new Date(parsedSession.expiresAt)
const expiryInSeconds = differenceInSeconds(parsedSession.expiresAt!, new Date())
await client.expire(`session:${parsedSession.handle}`, expiryInSeconds)
await client.expire(`user:${parsedSession.userId!}`, expiryInSeconds)
}
return parsedSession
} catch {
throw new Error("Can't get session")
}
}
const getSessions: SessionConfigMethods["getSessions"] = async (userId: string) => {
try {
const client = getRedisClient()
const sessionKeys = await client.lrange(`user:${userId}`, 0, -1)
const sessions = (
await Promise.all(
sessionKeys.map(async (handle) => {
const session = await getSession(handle)
return session
})
)
).filter(notEmpty)
return sessions
} catch {
throw new Error("Can't get sessions")
}
}
const createSession: SessionConfigMethods["createSession"] = async (session: SessionModel) => {
try {
const client = getRedisClient()
const expiryInSeconds = differenceInSeconds(session.expiresAt!, new Date())
await client.set(`session:${session.handle}`, JSON.stringify(session), "EX", expiryInSeconds)
await client.lpush(`user:${session.userId}`, session.handle)
await client.expire(`user:${session.userId}`, expiryInSeconds)
return session
} catch {
throw new Error("Can't create session")
}
}
const deleteSession: SessionConfigMethods["deleteSession"] = async (handle: string) => {
try {
const client = getRedisClient()
const session = await getSession(handle)
if (session) {
await client.lrem(`user:${session.userId}`, 0, handle)
await client.del(`session:${session.handle}`)
return session
}
return undefined
} catch {
throw new Error("Can't delete session")
}
}
const updateSession: SessionConfigMethods["updateSession"] = async (
handle: string,
session: SessionModel
) => {
try {
const client = getRedisClient()
const oldSession = await getSession(handle)
if (oldSession) {
const newSession = Object.assign(oldSession, session)
const expiryInSeconds = differenceInSeconds(newSession.expiresAt!, new Date())
await client.set(`session:${handle}`, JSON.stringify(newSession), "EX", expiryInSeconds)
await client.expire(`user:${session.userId}`, expiryInSeconds)
return newSession
} else {
return undefined
}
} catch {
throw new Error("Can't update session")
}
}
export default {
getSession,
getSessions,
createSession,
deleteSession,
updateSession,
} as SessionConfigMethods
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment