/ server / api / auth / github / link.get.ts
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  });