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.
47 lines
1.3 KiB
JavaScript
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'
|
|
})
|
|
}
|
|
})
|