| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- import { COOKIE_NAME, ONE_YEAR_MS } from "@shared/const";
- import type { Express, Request, Response } from "express";
- import * as db from "../db";
- import { getSessionCookieOptions } from "./cookies";
- import { sdk } from "./sdk";
- function getQueryParam(req: Request, key: string): string | undefined {
- const value = req.query[key];
- return typeof value === "string" ? value : undefined;
- }
- export function registerOAuthRoutes(app: Express) {
- app.get("/api/oauth/callback", async (req: Request, res: Response) => {
- const code = getQueryParam(req, "code");
- const state = getQueryParam(req, "state");
- if (!code || !state) {
- res.status(400).json({ error: "code and state are required" });
- return;
- }
- try {
- const tokenResponse = await sdk.exchangeCodeForToken(code, state);
- const userInfo = await sdk.getUserInfo(tokenResponse.accessToken);
- if (!userInfo.openId) {
- res.status(400).json({ error: "openId missing from user info" });
- return;
- }
- await db.upsertUser({
- openId: userInfo.openId,
- name: userInfo.name || null,
- email: userInfo.email ?? null,
- loginMethod: userInfo.loginMethod ?? userInfo.platform ?? null,
- lastSignedIn: new Date(),
- });
- const sessionToken = await sdk.createSessionToken(userInfo.openId, {
- name: userInfo.name || "",
- expiresInMs: ONE_YEAR_MS,
- });
- const cookieOptions = getSessionCookieOptions(req);
- res.cookie(COOKIE_NAME, sessionToken, { ...cookieOptions, maxAge: ONE_YEAR_MS });
- // Parse state to check for returnPath
- let redirectTo = "/";
- try {
- const decoded = Buffer.from(state, "base64").toString("utf-8");
- const parsed = JSON.parse(decoded);
- if (parsed.returnPath && typeof parsed.returnPath === "string" && parsed.returnPath.startsWith("/")) {
- redirectTo = parsed.returnPath;
- }
- } catch {
- // state is just the redirectUri string, redirect to /
- }
- res.redirect(302, redirectTo);
- } catch (error) {
- console.error("[OAuth] Callback failed", error);
- res.status(500).json({ error: "OAuth callback failed" });
- }
- });
- }
|