@rebasepro/server 0.10.0 → 0.10.1-canary.18115ba

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -119,6 +119,33 @@ export interface RefreshTokenInfo {
119
119
  createdAt: Date;
120
120
  userAgent?: string | null;
121
121
  ipAddress?: string | null;
122
+ /**
123
+ * The sign-in this token descends from. Every token minted by rotating
124
+ * this one carries the same id.
125
+ *
126
+ * Optional because a custom {@link TokenRepository} written against an
127
+ * older release does not supply it; the refresh endpoint then treats the
128
+ * token as a session of one, which costs reuse tolerance but still works.
129
+ */
130
+ sessionId?: string;
131
+ /**
132
+ * Set when this token was superseded by a rotation. Being superseded is
133
+ * not an error — a client whose response was lost still holds it — so it
134
+ * stays usable to mint a sibling for a short window after this instant.
135
+ */
136
+ rotatedAt?: Date | null;
137
+ /** Hard kill (logout, remote session revoke). Never usable again. */
138
+ revoked?: boolean;
139
+ /** When the sign-in happened; carried across rotations, unlike createdAt. */
140
+ sessionStartedAt?: Date;
141
+ }
142
+ /**
143
+ * Identity of the sign-in a refresh token belongs to, threaded through
144
+ * rotation so descendants stay grouped.
145
+ */
146
+ export interface RefreshTokenSession {
147
+ id: string;
148
+ startedAt: Date;
122
149
  }
123
150
  /**
124
151
  * Password reset token info
@@ -278,9 +305,45 @@ export interface RoleRepository {
278
305
  */
279
306
  export interface TokenRepository {
280
307
  /**
281
- * Create a new refresh token
308
+ * Create a new refresh token.
309
+ *
310
+ * `session` groups this token with the sign-in it descends from. It is
311
+ * optional so that repositories written against an older release keep
312
+ * satisfying this interface; implementations that ignore it degrade to one
313
+ * session per token.
314
+ */
315
+ createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string, session?: RefreshTokenSession): Promise<void>;
316
+ /**
317
+ * Mark a token as superseded by a rotation, WITHOUT making it unusable.
318
+ *
319
+ * The distinction from deletion is the entire point: a client that never
320
+ * received the rotated response still holds this token, and must be able
321
+ * to present it and be recognised. Implementations that omit this method
322
+ * fall back to {@link TokenRepository.deleteRefreshToken}, which restores
323
+ * the old, lossy behaviour.
324
+ */
325
+ markRefreshTokenRotated?(tokenHash: string): Promise<void>;
326
+ /**
327
+ * Hard-kill every token of one sign-in (logout, remote session revoke).
328
+ * Unlike rotation this is final — no grace, no replay.
329
+ */
330
+ revokeRefreshTokenSession?(sessionId: string): Promise<void>;
331
+ /**
332
+ * Drop tokens of a session that were superseded before `supersededBefore`,
333
+ * plus anything already expired. Keeps rotation from growing a row per
334
+ * refresh forever; called opportunistically, never load-bearing.
335
+ */
336
+ pruneRefreshTokens?(uid: string, sessionId: string, supersededBefore: Date): Promise<void>;
337
+ /**
338
+ * The instant before which every session of this user is void, or null if
339
+ * none is set. See `users.tokens_valid_after`.
340
+ */
341
+ getTokensValidAfter?(uid: string): Promise<Date | null>;
342
+ /**
343
+ * Void every session that began before `at`. Set alongside deleting the
344
+ * user's tokens so a rotation racing the delete cannot survive it.
282
345
  */
283
- createRefreshToken(uid: string, tokenHash: string, expiresAt: Date, userAgent?: string, ipAddress?: string): Promise<void>;
346
+ setTokensValidAfter?(uid: string, at: Date): Promise<void>;
284
347
  /**
285
348
  * Find a refresh token by hash
286
349
  */
@@ -65,6 +65,23 @@ export declare function generateRefreshToken(): string;
65
65
  * Hash a refresh token for database storage (don't store raw tokens)
66
66
  */
67
67
  export declare function hashRefreshToken(token: string): string;
68
+ /**
69
+ * The longest a cookie can live. Chrome (since 104) and RFC 6265bis silently
70
+ * rewrite any `Max-Age` beyond 400 days down to 400 days, so promising a
71
+ * browser more is not a stricter policy — it is a policy that differs from
72
+ * what is actually enforced, which is worse than knowing the ceiling.
73
+ */
74
+ export declare const MAX_COOKIE_AGE_MS: number;
75
+ /**
76
+ * How long a refresh token is valid for, in milliseconds.
77
+ *
78
+ * Every rotation issues a token with a fresh TTL, so this is a sliding window:
79
+ * a user who visits at all keeps their session indefinitely, and one who
80
+ * disappears loses it this long after their last visit. That is what both
81
+ * Firebase and Supabase do by default, and it is the behaviour people mean
82
+ * when they say they expect to still be signed in.
83
+ */
84
+ export declare function getRefreshTokenTtlMs(): number;
68
85
  /**
69
86
  * Calculate refresh token expiration date
70
87
  */
@@ -47,6 +47,22 @@ export interface AuthModuleConfig {
47
47
  * auth endpoints, and CORS must allow credentials (no `origin: "*"`).
48
48
  */
49
49
  cookieAuth?: CookieAuthConfig;
50
+ /**
51
+ * How long a refresh token stays usable after it has been rotated away,
52
+ * in seconds. Default 10, matching GoTrue's `refresh_token_reuse_interval`.
53
+ *
54
+ * Rotation is only safe if the client is guaranteed to receive the
55
+ * replacement, and no network guarantees that. A pod rolls mid-response, a
56
+ * laptop suspends, a second tab boots at the same instant — and the client
57
+ * is left holding a token the database has moved past. Within this window
58
+ * that client is handed a fresh token of the same session instead of a
59
+ * 401, which is the difference between a hiccup and being silently signed
60
+ * out of an app you were using.
61
+ *
62
+ * Widen it if your clients are flaky or your deploys are long; the cost is
63
+ * how long a captured token stays useful to someone who copied it.
64
+ */
65
+ refreshTokenReuseIntervalSeconds?: number;
50
66
  }
51
67
  /**
52
68
  * Configuration for httpOnly refresh-token cookies.