ghostguild-org/server/middleware/01.csrf.js
Jennie Robinson Faber 8a529a8e7c Add OIDC provider for Outline wiki SSO
Add oidc-provider with MongoDB adapter so ghostguild.org can act as
the identity provider for the self-hosted Outline wiki. Members
authenticate via the existing magic-link flow, with automatic SSO
when an active session exists. Includes interaction routes, well-known
discovery endpoint, and login page.
2026-03-01 15:46:01 +00:00

47 lines
1.3 KiB
JavaScript

import crypto from 'crypto'
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS'])
// Routes exempt from CSRF (external webhooks, magic link verify)
const EXEMPT_PREFIXES = [
'/api/helcim/webhook',
'/api/slack/webhook',
'/api/auth/verify',
'/oidc/',
]
function isExempt(path) {
return EXEMPT_PREFIXES.some(prefix => path.startsWith(prefix))
}
export default defineEventHandler((event) => {
const method = getMethod(event)
const path = getRequestURL(event).pathname
// Always set a CSRF token cookie if one doesn't exist
let csrfToken = getCookie(event, 'csrf-token')
if (!csrfToken) {
csrfToken = crypto.randomBytes(32).toString('hex')
setCookie(event, 'csrf-token', csrfToken, {
httpOnly: false, // Must be readable by JS to include in requests
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/'
})
}
// Only check state-changing methods
if (SAFE_METHODS.has(method)) return
if (!path.startsWith('/api/')) return
if (isExempt(path)) return
// Double-submit cookie check: header must match cookie
const headerToken = getHeader(event, 'x-csrf-token')
if (!headerToken || headerToken !== csrfToken) {
throw createError({
statusCode: 403,
statusMessage: 'CSRF token missing or invalid'
})
}
})