feat(auth): Session model + remember-me
Replace the single `user.refreshToken` column with a proper Session
table so users can have multiple concurrent sessions (phone, laptop,
etc.), each with their own refresh token, expiry, label, and
remember-me flag.
- Add Session model (id, userId, tokenHash, label, userAgent,
ipAddress, rememberMe, lastUsedAt, expiresAt).
- Drop `User.refreshToken` and `User.refreshTokenExpiresAt`.
- authService: new createSession/validateSession/rotateSession/
revokeSession/listUserSessions helpers; remove refresh-token-on-user
functions.
- sessionCookies helper now issues a session_id cookie alongside
access_token and refresh_token; rotateSessionCookies keeps the same
session id on refresh.
- Login form adds a "Keep me signed in for 30 days" checkbox;
TTL is 7d by default, 30d with remember-me.
- User-Agent parsed into a friendly label ("Chrome on Windows") for
the upcoming sessions page.
- hooks.server.ts, refresh endpoint, logout, register, oauth callback,
and onboarding all switched to the new session API.
This commit is contained in:
+19
-2
@@ -15,8 +15,6 @@ model User {
|
||||
avatarUrl String?
|
||||
authProvider String @default("local") // local | oauth
|
||||
role String @default("user") // admin | user
|
||||
refreshToken String?
|
||||
refreshTokenExpiresAt DateTime?
|
||||
onboardingComplete Boolean @default(false)
|
||||
trackRecentApps Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
@@ -29,6 +27,7 @@ model User {
|
||||
locale String?
|
||||
|
||||
groups UserGroup[]
|
||||
sessions Session[]
|
||||
createdApps App[]
|
||||
boards Board[]
|
||||
favorites UserFavorite[]
|
||||
@@ -42,6 +41,24 @@ model User {
|
||||
@@index([email])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
tokenHash String // bcrypt hash of the refresh token
|
||||
label String? // user-friendly, e.g. "Chrome on Windows"
|
||||
userAgent String?
|
||||
ipAddress String?
|
||||
rememberMe Boolean @default(false)
|
||||
lastUsedAt DateTime @default(now())
|
||||
expiresAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@index([expiresAt])
|
||||
}
|
||||
|
||||
model Group {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
|
||||
Reference in New Issue
Block a user