53 lines
1.5 KiB
TypeScript
53 lines
1.5 KiB
TypeScript
import fp from 'fastify-plugin';
|
|
import fastifyJwt from '@fastify/jwt';
|
|
import fastifyCookie from '@fastify/cookie';
|
|
import type { FastifyReply } from 'fastify';
|
|
import { env } from '../config/env.js';
|
|
import { UnauthorizedError } from '../utils/errors.js';
|
|
|
|
export const AUTH_COOKIE = 'fw_auth';
|
|
const AUTH_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; // 7 days
|
|
|
|
export default fp(async (app) => {
|
|
await app.register(fastifyCookie, {
|
|
secret: env.COOKIE_SECRET,
|
|
parseOptions: {},
|
|
});
|
|
|
|
await app.register(fastifyJwt, {
|
|
secret: env.JWT_SECRET,
|
|
cookie: { cookieName: AUTH_COOKIE, signed: false },
|
|
sign: { expiresIn: `${AUTH_COOKIE_MAX_AGE}s` },
|
|
});
|
|
|
|
app.decorate('authenticate', async (request) => {
|
|
try {
|
|
await request.jwtVerify({ onlyCookie: true });
|
|
} catch {
|
|
throw new UnauthorizedError();
|
|
}
|
|
});
|
|
|
|
// helpers for routes
|
|
app.decorate('setAuthCookie', ((reply: FastifyReply, token: string) => {
|
|
reply.setCookie(AUTH_COOKIE, token, {
|
|
httpOnly: true,
|
|
secure: env.NODE_ENV === 'production',
|
|
sameSite: 'lax',
|
|
path: '/',
|
|
maxAge: AUTH_COOKIE_MAX_AGE,
|
|
});
|
|
}) as never);
|
|
|
|
app.decorate('clearAuthCookie', ((reply: FastifyReply) => {
|
|
reply.clearCookie(AUTH_COOKIE, { path: '/' });
|
|
}) as never);
|
|
});
|
|
|
|
declare module 'fastify' {
|
|
interface FastifyInstance {
|
|
setAuthCookie: (reply: import('fastify').FastifyReply, token: string) => void;
|
|
clearAuthCookie: (reply: import('fastify').FastifyReply) => void;
|
|
}
|
|
}
|