link.get.ts
1 import { H3Event } from "h3"; 2 import { decrypt, encrypt } from "paseto-ts/v4"; 3 import { handleApiError} from "~~/server/utils/logging"; 4 5 export default defineEventHandler(async (event: H3Event) => { 6 const config = useRuntimeConfig(); 7 8 if (config.disableRegistering === "true") { 9 throw createError({ 10 statusCode: 403, 11 message: "Registration is currently disabled", 12 }); 13 } 14 15 if (!event.context.user) { 16 console.error("GitHub Link error: Unauthorized access attempt"); 17 throw createError({ 18 statusCode: 401, 19 message: "Unauthorized", 20 }); 21 } 22 23 const sessionCookie = getCookie(event, "session"); 24 25 if (!sessionCookie) { 26 throw createError({ 27 statusCode: 401, 28 message: "No session found", 29 }); 30 } 31 32 let userId: string; 33 try { 34 const { payload } = decrypt(config.pasetoKey, sessionCookie); 35 36 if ( 37 typeof payload !== "object" || 38 payload === null || 39 !("userId" in payload) 40 ) { 41 throw createError({ 42 statusCode: 401, 43 message: "Invalid token", 44 }); 45 } 46 userId = payload.userId; 47 } catch { 48 throw createError({ 49 statusCode: 401, 50 message: "Invalid token", 51 }); 52 } 53 54 const state = crypto.randomUUID(); 55 56 setCookie(event, "github_oauth_state", state, { 57 httpOnly: true, 58 secure: process.env.NODE_ENV === "production", 59 maxAge: 60 * 10, 60 path: "/", 61 sameSite: "lax", 62 }); 63 64 setCookie(event, "github_link_account", "true", { 65 httpOnly: true, 66 secure: process.env.NODE_ENV === "production", 67 maxAge: 60 * 10, 68 path: "/", 69 sameSite: "lax", 70 }); 71 72 const token = encrypt(config.pasetoKey, { 73 userId, 74 exp: new Date(Date.now() + 10 * 60 * 1000).toISOString(), 75 }); 76 77 setCookie(event, "github_link_session", token, { 78 httpOnly: true, 79 secure: process.env.NODE_ENV === "production", 80 maxAge: 60 * 10, 81 path: "/", 82 sameSite: "lax", 83 }); 84 85 const githubAuthUrl = new URL("https://github.com/login/oauth/authorize"); 86 githubAuthUrl.searchParams.append("client_id", config.githubClientId); 87 githubAuthUrl.searchParams.append("redirect_uri", config.githubRedirectUri); 88 githubAuthUrl.searchParams.append("state", state); 89 githubAuthUrl.searchParams.append("scope", "read:user user:email"); 90 91 try { 92 return { url: githubAuthUrl.toString() }; 93 } catch (error) { 94 const detailedMessage = error instanceof Error ? error.message : "An unknown error occurred while generating GitHub auth URL."; 95 throw handleApiError(500, `Failed to generate GitHub auth URL: ${detailedMessage}`, "Could not initiate GitHub linking. Please try again."); 96 } 97 });