tcl-guessr/src/routes/login/callback/+server.ts

55 lines
1.8 KiB
TypeScript

import { error, redirect } from "@sveltejs/kit";
import { discord, type DiscordUser } from "$lib/auth/discord";
import { OAuth2RequestError, type OAuth2Tokens } from "arctic";
import { createSession, generateSessionToken } from "$lib/auth/session";
import { setSessionTokenCookie } from "$lib/auth/cookie";
import { destr } from "destr";
import type { RequestHandler } from "./$types";
import type { CookieData } from "$lib/auth";
export const GET: RequestHandler = async ({ platform, url, cookies, fetch }) => {
const db = platform?.env?.TCL_GUESSR_D1 ?? null;
if (db === null) error(500, "could not access D1");
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
const cookie = destr<CookieData>(cookies.get("discord_oauth_state")) ?? null;
if (code === null || state === null || cookie === null) {
error(400, "missing things from oauth2 response");
}
if (state !== cookie.state) {
error(400, "state does not match");
}
let tokens: OAuth2Tokens;
try {
tokens = await discord.validateAuthorizationCode(code);
} catch (e) {
if (e instanceof OAuth2RequestError) {
error(400, e.message);
} else {
error(400, "could not validate auth code");
}
}
const discordUser: DiscordUser = await fetch("https://discord.com/api/v10/users/@me", {
headers: {
Authorization: `Bearer ${tokens.accessToken()}`,
},
}).then((r) => r.json());
await db
.prepare(
"INSERT INTO user(id, name, avatar_hash) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET name=excluded.name, avatar_hash=excluded.avatar_hash;",
)
.bind(discordUser.id, discordUser.username, discordUser.avatar)
.run();
const sessionToken = generateSessionToken();
const session = await createSession(sessionToken, discordUser.id, db);
setSessionTokenCookie(cookies, sessionToken, session.expiresAt);
redirect(302, cookie.next);
};