persist refresh tokens in auth database
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-07-06 09:16:14 +09:00
parent 9521912bfc
commit 1afd8096c8
+38 -2
View File
@@ -453,22 +453,58 @@ export async function verifyPasswordResetCode(email: string, code: string): Prom
export async function createRefreshToken(userId: string): Promise<string> {
const token = createOpaqueToken()
await redis.set(refreshTokenKey(token), JSON.stringify({ userId }), 'EX', config.refreshTokenTtlSeconds)
const expiresAt = new Date(Date.now() + config.refreshTokenTtlSeconds * 1000)
await Promise.all([
redis.set(refreshTokenKey(token), JSON.stringify({ userId }), 'EX', config.refreshTokenTtlSeconds),
prisma.refreshToken.create({
data: {
userId,
tokenHash: hashToken(token),
expiresAt
}
})
])
return token
}
export async function rotateRefreshToken(refreshToken: string): Promise<AuthUser | null> {
const tokenHash = hashToken(refreshToken)
const tokenJson = await redis.send('GETDEL', [refreshTokenKey(refreshToken)])
if (typeof tokenJson !== 'string') return null
const token = parseStoredRefreshToken(tokenJson)
if (!token) return null
const storedToken = await prisma.refreshToken.findUnique({
where: { tokenHash },
select: { id: true, userId: true, revokedAt: true, expiresAt: true }
})
if (!storedToken || storedToken.userId !== token.userId || storedToken.revokedAt || storedToken.expiresAt <= new Date()) {
return null
}
await prisma.refreshToken.update({
where: { id: storedToken.id },
data: { revokedAt: new Date() }
})
return findUserById(token.userId)
}
export async function revokeRefreshToken(refreshToken: string): Promise<void> {
await redis.del(refreshTokenKey(refreshToken))
await Promise.all([
redis.del(refreshTokenKey(refreshToken)),
prisma.refreshToken.updateMany({
where: {
tokenHash: hashToken(refreshToken),
revokedAt: null
},
data: { revokedAt: new Date() }
})
])
}
export async function createHandoffToken(userId: string, audienceApp: string): Promise<string> {