remember me fix
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
*
|
*
|
||||||
* Timing Decisions:
|
* Timing Decisions:
|
||||||
* - 15m access: Balance between security (short exposure) and UX (not too frequent refreshes)
|
* - 15m access: Balance between security (short exposure) and UX (not too frequent refreshes)
|
||||||
* - 1d session: DB cleanup for session-only logins (cookie expires on browser close anyway)
|
* - 7d session: DB expiry for non-remember-me (cookie is session-only but accommodates users who keep browser open)
|
||||||
* - 90d remember: Extended convenience for trusted devices (both DB and cookie persist)
|
* - 90d remember: Extended convenience for trusted devices (both DB and cookie persist)
|
||||||
* - 5s reuse window: Handles race conditions in distributed systems
|
* - 5s reuse window: Handles race conditions in distributed systems
|
||||||
*/
|
*/
|
||||||
@@ -27,12 +27,12 @@ export const AUTH_CONFIG = {
|
|||||||
ACCESS_TOKEN_EXPIRY_DEV: "2m" as const, // 2 minutes for faster testing
|
ACCESS_TOKEN_EXPIRY_DEV: "2m" as const, // 2 minutes for faster testing
|
||||||
|
|
||||||
// Refresh Token (opaque token in separate cookie)
|
// Refresh Token (opaque token in separate cookie)
|
||||||
REFRESH_TOKEN_EXPIRY_SHORT: "1d" as const, // 1 day (DB expiry, cookie is session-only - non-remember me)
|
REFRESH_TOKEN_EXPIRY_SHORT: "7d" as const, // 7 days (DB expiry for non-remember me - accommodates users who keep browser open)
|
||||||
REFRESH_TOKEN_EXPIRY_LONG: "90d" as const, // 90 days (remember me - both DB and cookie persist)
|
REFRESH_TOKEN_EXPIRY_LONG: "90d" as const, // 90 days (remember me - both DB and cookie persist)
|
||||||
|
|
||||||
// Security Settings
|
// Security Settings
|
||||||
REFRESH_TOKEN_ROTATION_ENABLED: true, // Enable token rotation
|
REFRESH_TOKEN_ROTATION_ENABLED: true, // Enable token rotation
|
||||||
MAX_ROTATION_COUNT: 100, // Max rotations before forcing re-login
|
MAX_ROTATION_COUNT: 1000, // Max rotations before forcing re-login (1000 * 15m = 10.4 days in prod, 1000 * 2m = 33 hours in dev)
|
||||||
REFRESH_TOKEN_REUSE_WINDOW_MS: 5000, // 5s grace period for race conditions
|
REFRESH_TOKEN_REUSE_WINDOW_MS: 5000, // 5s grace period for race conditions
|
||||||
|
|
||||||
// Session Cleanup (serverless-friendly opportunistic cleanup)
|
// Session Cleanup (serverless-friendly opportunistic cleanup)
|
||||||
|
|||||||
@@ -910,7 +910,7 @@ export const authRouter = createTRPCRouter({
|
|||||||
emailRegistration: publicProcedure
|
emailRegistration: publicProcedure
|
||||||
.input(registerUserSchema)
|
.input(registerUserSchema)
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
const { email, password, passwordConfirmation } = input;
|
const { email, password, passwordConfirmation, rememberMe } = input;
|
||||||
|
|
||||||
// Apply rate limiting
|
// Apply rate limiting
|
||||||
const clientIP = getClientIP(getH3Event(ctx));
|
const clientIP = getClientIP(getH3Event(ctx));
|
||||||
@@ -977,7 +977,7 @@ export const authRouter = createTRPCRouter({
|
|||||||
await createAuthSession(
|
await createAuthSession(
|
||||||
getH3Event(ctx),
|
getH3Event(ctx),
|
||||||
userId,
|
userId,
|
||||||
true, // Always use persistent sessions
|
rememberMe ?? true, // Default to persistent sessions for registration
|
||||||
clientIP,
|
clientIP,
|
||||||
userAgent
|
userAgent
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export const registerUserSchema = z
|
|||||||
.object({
|
.object({
|
||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
password: securePasswordSchema,
|
password: securePasswordSchema,
|
||||||
passwordConfirmation: z.string().min(VALIDATION_CONFIG.MIN_PASSWORD_LENGTH)
|
passwordConfirmation: z.string().min(VALIDATION_CONFIG.MIN_PASSWORD_LENGTH),
|
||||||
|
rememberMe: z.boolean().optional().default(true)
|
||||||
})
|
})
|
||||||
.refine((data) => data.password === data.passwordConfirmation, {
|
.refine((data) => data.password === data.passwordConfirmation, {
|
||||||
message: "Passwords do not match",
|
message: "Passwords do not match",
|
||||||
@@ -60,7 +61,8 @@ export const registerUserSchema = z
|
|||||||
*/
|
*/
|
||||||
export const loginUserSchema = z.object({
|
export const loginUserSchema = z.object({
|
||||||
email: z.string().email(),
|
email: z.string().email(),
|
||||||
password: z.string().min(1, "Password is required")
|
password: z.string().min(1, "Password is required"),
|
||||||
|
rememberMe: z.boolean().optional().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user