Scratch space for learning atproto app development

Fold src/auth/session into src/routes

Changed files
+36 -64
src
-61
src/auth/session.ts
···
-
import assert from 'node:assert'
-
import type { IncomingMessage, ServerResponse } from 'node:http'
-
import { getIronSession } from 'iron-session'
-
import { env } from '#/lib/env'
-
import { AppContext } from '#/index'
-
-
export type Session = { did: string }
-
-
export async function createSession(
-
req: IncomingMessage,
-
res: ServerResponse<IncomingMessage>,
-
did: string
-
) {
-
const session = await getSessionRaw(req, res)
-
assert(!session.did, 'session already exists')
-
session.did = did
-
await session.save()
-
return { did: session.did }
-
}
-
-
export async function destroySession(
-
req: IncomingMessage,
-
res: ServerResponse<IncomingMessage>
-
) {
-
const session = await getSessionRaw(req, res)
-
await session.destroy()
-
return null
-
}
-
-
export async function getSession(
-
req: IncomingMessage,
-
res: ServerResponse<IncomingMessage>
-
) {
-
const session = await getSessionRaw(req, res)
-
if (!session.did) return null
-
return { did: session.did }
-
}
-
-
export async function getSessionAgent(
-
req: IncomingMessage,
-
res: ServerResponse<IncomingMessage>,
-
ctx: AppContext
-
) {
-
const session = await getSessionRaw(req, res)
-
if (!session.did) return null
-
return await ctx.oauthClient.restore(session.did).catch(async (err) => {
-
ctx.logger.warn({ err }, 'oauth restore failed')
-
await destroySession(req, res)
-
return null
-
})
-
}
-
-
async function getSessionRaw(
-
req: IncomingMessage,
-
res: ServerResponse<IncomingMessage>
-
) {
-
return await getIronSession<Session>(req, res, {
-
cookieName: 'sid',
-
password: env.COOKIE_SECRET,
-
})
-
}
+36 -3
src/routes.ts
···
+
import assert from 'node:assert'
import path from 'node:path'
+
import type { IncomingMessage, ServerResponse } from 'node:http'
import { OAuthResolverError } from '@atproto/oauth-client-node'
import { isValidHandle } from '@atproto/syntax'
import express from 'express'
-
import { createSession, destroySession, getSessionAgent } from '#/auth/session'
+
import { getIronSession } from 'iron-session'
import type { AppContext } from '#/index'
import { home } from '#/pages/home'
import { login } from '#/pages/login'
+
import { env } from '#/lib/env'
import { page } from '#/lib/view'
import * as Status from '#/lexicon/types/com/example/status'
+
type Session = { did: string }
+
// Helper function for defining routes
const handler =
(fn: express.Handler) =>
···
}
}
+
// Helper function to get the Atproto Agent for the active session
+
async function getSessionAgent(
+
req: IncomingMessage,
+
res: ServerResponse<IncomingMessage>,
+
ctx: AppContext
+
) {
+
const session = await getIronSession<Session>(req, res, {
+
cookieName: 'sid',
+
password: env.COOKIE_SECRET,
+
})
+
if (!session.did) return null
+
return await ctx.oauthClient.restore(session.did).catch(async (err) => {
+
ctx.logger.warn({ err }, 'oauth restore failed')
+
await session.destroy()
+
return null
+
})
+
}
+
export const createRouter = (ctx: AppContext) => {
const router = express.Router()
···
const params = new URLSearchParams(req.originalUrl.split('?')[1])
try {
const { agent } = await ctx.oauthClient.callback(params)
-
await createSession(req, res, agent.accountDid)
+
const session = await getIronSession<Session>(req, res, {
+
cookieName: 'sid',
+
password: env.COOKIE_SECRET,
+
})
+
assert(!session.did, 'session already exists')
+
session.did = agent.accountDid
+
await session.save()
} catch (err) {
ctx.logger.error({ err }, 'oauth callback failed')
return res.redirect('/?error')
···
router.post(
'/logout',
handler(async (req, res) => {
-
await destroySession(req, res)
+
const session = await getIronSession<Session>(req, res, {
+
cookieName: 'sid',
+
password: env.COOKIE_SECRET,
+
})
+
await session.destroy()
return res.redirect('/')
})
)