import db from "@server/db"; import { JWT_SECRET } from "@server/lib/consts"; import github from "@server/lib/github"; import queue from "@server/lib/queue"; import { users } from "@server/models"; import { CreateUser } from "@server/models/users"; import { eq } from "drizzle-orm"; import { Hono } from "hono"; import { setCookie } from "hono/cookie"; import * as jwt from "hono/jwt"; import { auth as authMiddleware } from "../middlewares/auth"; const { GITHUB_CLIENT_ID, GITHUB_SECRET_KEY } = import.meta.env; export const auth = new Hono() /** * Redirect to github oauth */ .get("/login", (c) => { return c.redirect( "https://github.com/login/oauth/authorize?client_id=" + GITHUB_CLIENT_ID ); }) /** * Auth callback */ .get("/callback", async (c) => { const code = c.req.query("code"); const result = await github.fetch("login/oauth/access_token", { params: { client_id: GITHUB_CLIENT_ID, client_secret: GITHUB_SECRET_KEY, code, }, headers: { accept: "application/json", }, }); const accessToken = result.access_token; const ghUser = await github.fetch("user", { ghApi: true, headers: { accept: "application/json", Authorization: "Bearer " + accessToken, }, }); const userData: CreateUser = { username: ghUser.login, name: ghUser.name || ghUser.login, avatar: ghUser.avatar_url, location: ghUser.location, accessToken, githubId: ghUser.id, followers: ghUser.followers, following: ghUser.following, }; const [user] = await db .insert(users) .values(userData) .onConflictDoUpdate({ target: users.username, set: userData, }) .returning(); if (!user) { throw new Error("Auth user failed!"); } // Fetch latest user profile await queue.add( "fetchUserProfile", { userId: user.id }, { jobId: `fetchUserProfile:${user.id}` } ); await queue.add( "fetchUserRepos", { userId: user.id }, { jobId: `fetchUserRepos:${user.id}` } ); const authToken = await jwt.sign({ id: user.id }, JWT_SECRET); setCookie(c, "token", authToken, { httpOnly: true }); return c.redirect("/"); }) /** * Get authenticated user */ .get("/user", authMiddleware(), async (c) => { const userId = c.get("userId"); if (!userId) { return c.json(null); } const [user] = await db.select().from(users).where(eq(users.id, userId)); return c.json(user ? { ...user, accessToken: undefined } : null); }) /** * Logout */ .get("/logout", authMiddleware({ required: true }), async (c) => { setCookie(c, "token", "", { httpOnly: true }); return c.redirect("/"); });