Cap refresh chain lifetime via RefreshChainAbsoluteTTL
Sessions had an absolute cap (created_at + SessionAbsoluteTTL) but the JWT path only had per-token TTL on the refresh row, letting a well-behaved client refresh indefinitely. Add chain_started_at to authkit_tokens, copy it forward on every rotation, and reject in RefreshJWT when now > chainStartedAt + RefreshChainAbsoluteTTL. Default 30d, mirroring SessionAbsoluteTTL. Schema, verifier, queries, model, and integration test updated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d3c5367492
commit
ca5525d4bd
11 changed files with 129 additions and 53 deletions
|
|
@ -121,17 +121,17 @@ func buildQueries(t Tables) queries {
|
|||
|
||||
// tokens
|
||||
createToken: `INSERT INTO ` + t.Tokens + `
|
||||
(hash, kind, user_id, chain_id, consumed_at, attempts_remaining, created_at, expires_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
||||
(hash, kind, user_id, chain_id, chain_started_at, consumed_at, attempts_remaining, created_at, expires_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
|
||||
consumeToken: `UPDATE ` + t.Tokens + `
|
||||
SET consumed_at = $1
|
||||
WHERE kind = $2 AND hash = $3 AND consumed_at IS NULL AND expires_at > $4
|
||||
RETURNING hash, kind, user_id, chain_id, consumed_at, attempts_remaining, created_at, expires_at`,
|
||||
getToken: `SELECT hash, kind, user_id, chain_id, consumed_at, attempts_remaining, created_at, expires_at
|
||||
RETURNING hash, kind, user_id, chain_id, chain_started_at, consumed_at, attempts_remaining, created_at, expires_at`,
|
||||
getToken: `SELECT hash, kind, user_id, chain_id, chain_started_at, consumed_at, attempts_remaining, created_at, expires_at
|
||||
FROM ` + t.Tokens + ` WHERE kind = $1 AND hash = $2`,
|
||||
// getOTPForUser returns the most recent unconsumed, unexpired OTP for
|
||||
// the user, used to verify a code by hash-comparing client input.
|
||||
getOTPForUser: `SELECT hash, kind, user_id, chain_id, consumed_at, attempts_remaining, created_at, expires_at
|
||||
getOTPForUser: `SELECT hash, kind, user_id, chain_id, chain_started_at, consumed_at, attempts_remaining, created_at, expires_at
|
||||
FROM ` + t.Tokens + `
|
||||
WHERE kind = $1 AND user_id = $2 AND consumed_at IS NULL AND expires_at > $3
|
||||
ORDER BY created_at DESC LIMIT 1`,
|
||||
|
|
@ -146,7 +146,7 @@ func buildQueries(t Tables) queries {
|
|||
consumeOTPByID: `UPDATE ` + t.Tokens + `
|
||||
SET consumed_at = $1
|
||||
WHERE kind = $2 AND hash = $3 AND consumed_at IS NULL AND expires_at > $1
|
||||
RETURNING hash, kind, user_id, chain_id, consumed_at, attempts_remaining, created_at, expires_at`,
|
||||
RETURNING hash, kind, user_id, chain_id, chain_started_at, consumed_at, attempts_remaining, created_at, expires_at`,
|
||||
deleteByChain: `DELETE FROM ` + t.Tokens + ` WHERE chain_id = $1`,
|
||||
deleteExpiredTokens: `DELETE FROM ` + t.Tokens + ` WHERE expires_at <= $1`,
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue