Files
GearBox/src/server/routes/auth.ts
Jean-Luc Makiola 3b29248845
Some checks failed
CI / ci (push) Failing after 1m8s
CI / deploy (push) Has been skipped
CI / e2e (push) Has been skipped
fix: return database user ID from /api/auth/me instead of Logto sub
The /me endpoint was returning auth.sub (Logto's opaque string) as the
user ID, but the frontend and other API endpoints expect numeric DB IDs.
This caused "can't access property 'id', w[0] is undefined" after login.

Also documents Logto OIDC setup requirements (scopes, env vars) in
CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 22:16:59 +02:00

94 lines
2.6 KiB
TypeScript

import { getAuth } from "@hono/oidc-auth";
import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";
import { z } from "zod";
import { updateProfileSchema } from "../../shared/schemas.ts";
import { parseId } from "../lib/params.ts";
import { requireAuth } from "../middleware/auth.ts";
import {
createApiKey,
deleteApiKey,
getOrCreateUser,
listApiKeys,
} from "../services/auth.service.ts";
import { updateProfile } from "../services/profile.service.ts";
type Env = { Variables: { db?: any; userId?: number } };
const createKeySchema = z.object({ name: z.string().min(1) });
const app = new Hono<Env>();
// ── Auth Status ──────────────────────────────────────────────────────
app.get("/me", async (c) => {
const auth = await getAuth(c);
if (auth) {
const db = c.get("db");
const user = await getOrCreateUser(db, auth.sub);
return c.json({
user: { id: user.id, email: auth.email },
authenticated: true,
});
}
return c.json({ user: null, authenticated: false });
});
// ── API Key Management (protected) ───────────────────────────────────
app.get("/keys", requireAuth, async (c) => {
const db = c.get("db");
const userId = c.get("userId")!;
const keys = await listApiKeys(db, userId);
return c.json(keys);
});
app.post(
"/keys",
requireAuth,
zValidator("json", createKeySchema),
async (c) => {
const db = c.get("db");
const userId = c.get("userId")!;
const { name } = c.req.valid("json");
const result = await createApiKey(db, userId, name);
return c.json(
{
id: result.id,
name: result.name,
key: result.rawKey,
prefix: result.keyPrefix,
},
201,
);
},
);
app.delete("/keys/:id", requireAuth, async (c) => {
const db = c.get("db");
const userId = c.get("userId")!;
const id = parseId(c.req.param("id"));
if (!id) return c.json({ error: "Invalid key ID" }, 400);
await deleteApiKey(db, userId, id);
return c.json({ ok: true });
});
// ── Profile Update (protected) ──────────────────────────────────────
app.put(
"/profile",
requireAuth,
zValidator("json", updateProfileSchema),
async (c) => {
const db = c.get("db");
const userId = c.get("userId")!;
const data = c.req.valid("json");
const updated = await updateProfile(db, userId, data);
if (!updated) return c.json({ error: "User not found" }, 404);
return c.json(updated);
},
);
export const authRoutes = app;