language-learning-app/frontend/src/hooks.server.ts

45 lines
1.4 KiB
TypeScript
Raw Normal View History

import { decodeJwt, jwtVerify } from 'jose';
2026-03-26 20:46:15 +00:00
import { redirect, type Handle } from '@sveltejs/kit';
import { PRIVATE_JWT_SECRET } from '$env/static/private';
2026-03-25 21:09:38 +00:00
import { client } from './lib/apiClient.ts';
import { COOKIE_NAME_AUTH_TOKEN } from '$lib/auth/index.ts';
async function verifyJwt(token: string, secret: string): Promise<boolean> {
const encodedSecret = new TextEncoder().encode(secret);
return await jwtVerify(token, encodedSecret)
.then(() => true)
.catch((e) => {
console.log(`Caught error while validating JWT: ${e}`);
return false;
});
}
2026-03-25 21:09:38 +00:00
function getJwtPayload(jwt: string): { isAdmin: boolean } {
const decodeResult = decodeJwt<{ is_admin: boolean }>(jwt);
return { isAdmin: decodeResult.is_admin };
2026-03-26 20:46:15 +00:00
}
2026-03-25 21:09:38 +00:00
export const handle: Handle = async ({ event, resolve }) => {
event.locals.apiClient = client;
const rawToken = event.cookies.get(COOKIE_NAME_AUTH_TOKEN);
const isValid = rawToken ? await verifyJwt(rawToken, PRIVATE_JWT_SECRET) : false;
2026-03-26 20:46:15 +00:00
event.locals.authToken = isValid ? rawToken! : null;
2026-03-25 21:09:38 +00:00
if (isValid && rawToken) {
const payload = getJwtPayload(rawToken);
event.locals.isAdmin = payload.isAdmin;
} else {
event.locals.isAdmin = false;
console.log(`Not valid and no token`);
}
const { pathname } = event.url;
if ((pathname.startsWith('/app') || pathname.startsWith('/admin')) && !isValid) {
console.log(`Redirecting to login`);
2026-03-26 20:46:15 +00:00
return redirect(307, '/login');
}
2026-03-25 21:09:38 +00:00
2026-03-26 20:46:15 +00:00
return resolve(event);
2026-03-25 21:09:38 +00:00
};