feat(auth): add 'remember me' functionality and token refresh logic
This commit is contained in:
@@ -40,8 +40,8 @@ const app = Fastify({
|
||||
const origins = env.CORS_ORIGINS.split(",").map((o) => o.trim()).filter(Boolean);
|
||||
|
||||
// Auth token TTLs (hardcoded - no need for user configuration)
|
||||
const accessTtlMinutes = 15; // Access token: 15 minutes
|
||||
const refreshTtlDays = 14; // Refresh token: 14 days
|
||||
const accessTtlMinutes = env.ACCESS_TOKEN_TTL_MINUTES; // Access token TTL
|
||||
const refreshTtlDays = env.REFRESH_TOKEN_TTL_DAYS; // Refresh token TTL
|
||||
|
||||
const baseCookieOptions: CookieSerializeOptions = {
|
||||
httpOnly: true,
|
||||
|
||||
@@ -23,6 +23,10 @@ const EnvSchema = z.object({
|
||||
JWT_SECRET: z.string().min(10).optional(),
|
||||
REFRESH_SECRET: z.string().min(10).optional(),
|
||||
COOKIE_SECRET: z.string().min(10).optional(),
|
||||
|
||||
// Token TTL settings
|
||||
ACCESS_TOKEN_TTL_MINUTES: z.string().transform((v) => parseInt(v, 10)).default("15"),
|
||||
REFRESH_TOKEN_TTL_DAYS: z.string().transform((v) => parseInt(v, 10)).default("7"),
|
||||
});
|
||||
|
||||
export type Env = z.infer<typeof EnvSchema>;
|
||||
|
||||
@@ -36,6 +36,7 @@ const registerSchema = z.object({
|
||||
const loginSchema = z.object({
|
||||
username: z.string().min(1, "Username is required"),
|
||||
password: z.string().min(1, "Password is required"),
|
||||
rememberMe: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
const updateProfileSchema = z.object({
|
||||
@@ -141,7 +142,7 @@ export async function authRoutes(app: FastifyInstance) {
|
||||
});
|
||||
}
|
||||
|
||||
const { username, password } = parsed.data;
|
||||
const { username, password, rememberMe } = parsed.data;
|
||||
|
||||
// Find user by username
|
||||
const [user] = await db.select().from(users).where(eq(users.username, username));
|
||||
@@ -196,11 +197,19 @@ export async function authRoutes(app: FastifyInstance) {
|
||||
{ expiresIn: `${refreshTtlDays}d`, key: app.config.refreshSecret }
|
||||
);
|
||||
|
||||
app.log.info(`User logged in: ${username}`);
|
||||
app.log.info(`User logged in: ${username} (rememberMe: ${rememberMe})`);
|
||||
|
||||
// Cookie options: with maxAge for "remember me", without for session cookie
|
||||
const accessCookieOptions = rememberMe
|
||||
? app.config.cookieOptions
|
||||
: { ...app.config.cookieOptions, maxAge: undefined };
|
||||
const refreshCookieOptions = rememberMe
|
||||
? app.config.refreshCookieOptions
|
||||
: { ...app.config.refreshCookieOptions, maxAge: undefined };
|
||||
|
||||
return reply
|
||||
.setCookie("access_token", accessToken, app.config.cookieOptions)
|
||||
.setCookie("refresh_token", refreshToken, app.config.refreshCookieOptions)
|
||||
.setCookie("access_token", accessToken, accessCookieOptions)
|
||||
.setCookie("refresh_token", refreshToken, refreshCookieOptions)
|
||||
.send({
|
||||
ok: true,
|
||||
user: {
|
||||
|
||||
Reference in New Issue
Block a user