import { User } from "../../models/User"; import jwt from "jsonwebtoken"; import type { OAuthTokenResponse, GhostGuildUserInfo, } from "../../../types/auth"; export default defineEventHandler(async (event) => { const config = useRuntimeConfig(); const query = getQuery(event); // Verify state for CSRF protection const storedState = getCookie(event, "oauth_state"); if (!storedState || storedState !== query.state) { return sendRedirect(event, "/login?error=invalid_state"); } // Clear the state cookie deleteCookie(event, "oauth_state"); // Exchange authorization code for access token try { const tokenResponse = await $fetch( `${config.ghostguildApiUrl}/oauth/token`, { method: "POST", body: { grant_type: "authorization_code", code: query.code, redirect_uri: `${config.public.siteUrl}/api/auth/callback`, client_id: config.ghostguildClientId, client_secret: config.ghostguildClientSecret, }, }, ); // Get user information from Ghost Guild const userInfo = await $fetch( `${config.ghostguildApiUrl}/user/me`, { headers: { Authorization: `Bearer ${tokenResponse.access_token}`, }, }, ); // Find or create user in our database let user = await User.findOne({ ghostguildId: userInfo.id }); if (!user) { user = await User.create({ ghostguildId: userInfo.id, email: userInfo.email, username: userInfo.username, displayName: userInfo.displayName || userInfo.username, avatar: userInfo.avatar, roles: userInfo.roles || ["member"], permissions: { canEdit: userInfo.roles?.includes("member") || false, canModerate: userInfo.roles?.includes("moderator") || false, canAdmin: userInfo.roles?.includes("admin") || false, }, lastLogin: new Date(), }); } else { // Update existing user user.displayName = userInfo.displayName || userInfo.username; user.avatar = userInfo.avatar; user.roles = userInfo.roles || ["member"]; user.lastLogin = new Date(); await user.save(); } // Create JWT token const token = jwt.sign( { userId: user._id, username: user.username, roles: user.roles, permissions: user.permissions, }, config.jwtSecret as string, { expiresIn: "7d" }, ); // Set JWT as httpOnly cookie setCookie(event, "auth-token", token, { httpOnly: true, secure: true, sameSite: "lax", maxAge: 60 * 60 * 24 * 7, // 7 days }); // Redirect to dashboard or home return sendRedirect(event, "/dashboard"); } catch (error) { console.error("OAuth callback error:", error); return sendRedirect(event, "/login?error=authentication_failed"); } });