77 "github.com/gofrs/uuid"
88
99 "github.com/supabase/auth/internal/api/apierrors"
10+ "github.com/supabase/auth/internal/crypto"
1011 "github.com/supabase/auth/internal/hooks/v0hooks"
1112 "github.com/supabase/auth/internal/metering"
1213 "github.com/supabase/auth/internal/models"
@@ -303,7 +304,8 @@ func (a *API) updateMFASessionAndClaims(r *http.Request, tx *storage.Connection,
303304 config := a .config
304305 var tokenString string
305306 var expiresAt int64
306- var refreshToken * models.RefreshToken
307+ var issuedRefreshToken string
308+
307309 currentClaims := getClaims (ctx )
308310 sessionId , err := uuid .FromString (currentClaims .SessionId )
309311 if err != nil {
@@ -325,11 +327,36 @@ func (a *API) updateMFASessionAndClaims(r *http.Request, tx *storage.Connection,
325327 if err := tx .Load (user , "Identities" ); err != nil {
326328 return err
327329 }
328- // Swap to ensure current token is the latest one
329- refreshToken , terr = models .GrantRefreshTokenSwap (config .AuditLog , r , tx , user , currentToken )
330- if terr != nil {
331- return terr
330+
331+ // issue a new refresh token on successful verification
332+ if session .RefreshTokenHmacKey != nil && session .RefreshTokenCounter != nil {
333+ signingKey , _ , terr := session .GetRefreshTokenHmacKey (config .Security .DBEncryption )
334+ if terr != nil {
335+ return apierrors .NewInternalServerError ("Failed to get session's refresh token key" ).WithInternalError (terr )
336+ }
337+
338+ counter := * session .RefreshTokenCounter + 1
339+ session .RefreshTokenCounter = & counter
340+
341+ issuedRefreshToken = (& crypto.RefreshToken {
342+ Version : 0 ,
343+ SessionID : session .ID ,
344+ Counter : * session .RefreshTokenCounter ,
345+ }).Encode (signingKey )
346+
347+ if terr := session .UpdateOnlyRefreshToken (tx ); terr != nil {
348+ return apierrors .NewInternalServerError ("Failed to update session" ).WithInternalError (terr )
349+ }
350+ } else {
351+ // Legacy RTs: swap to ensure current token is the latest one
352+ refreshToken , terr := models .GrantRefreshTokenSwap (config .AuditLog , r , tx , user , currentToken )
353+ if terr != nil {
354+ return terr
355+ }
356+
357+ issuedRefreshToken = refreshToken .Token
332358 }
359+
333360 aal , _ , terr := session .CalculateAALAndAMR (user )
334361 if terr != nil {
335362 return terr
@@ -362,7 +389,7 @@ func (a *API) updateMFASessionAndClaims(r *http.Request, tx *storage.Connection,
362389 TokenType : "bearer" ,
363390 ExpiresIn : config .JWT .Exp ,
364391 ExpiresAt : expiresAt ,
365- RefreshToken : refreshToken . Token ,
392+ RefreshToken : issuedRefreshToken ,
366393 User : user ,
367394 }, nil
368395}
0 commit comments