fix: a self-service password change revokes every OAuth grant, however recently refreshed
ChangePassword fired the access-revoked event with Before = the calling session's iat, so an OAuth/MCP grant whose client refreshed it after that instant kept working. Before is now the instant of the request; the stored tokens_valid_after still keeps the calling session.
This commit is contained in:
@@ -716,10 +716,12 @@ func ChangePassword(app *backpack.App) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
// The cutoff keeps the current session (issued at iat) and every
|
||||
// token issued since its sign-in second; the access-revoked event
|
||||
// revokes OAuth grants created before that second, in the same
|
||||
// transaction.
|
||||
// session token issued since that second. OAuth grants are revoked
|
||||
// as of now, whatever their age: the request needs none, and a
|
||||
// grant its client refreshed after iat would otherwise survive the
|
||||
// change (its rotated tokens are newer than the session).
|
||||
cutoff := iat.Add(-time.Second)
|
||||
revokedAt := time.Now()
|
||||
if err := lagoon.Transaction(r.Context(), gdb, func(ctx context.Context, tx *gorm.DB) error {
|
||||
if err := tx.WithContext(ctx).Model(&user).Updates(map[string]any{
|
||||
"password": hashed,
|
||||
@@ -729,7 +731,7 @@ func ChangePassword(app *backpack.App) http.HandlerFunc {
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return classes.FireAccessRevoked(ctx, app, tx, []uint{user.ID}, cutoff.Add(time.Second), classes.AccessRevokedPasswordChanged)
|
||||
return classes.FireAccessRevoked(ctx, app, tx, []uint{user.ID}, revokedAt, classes.AccessRevokedPasswordChanged)
|
||||
}); err != nil {
|
||||
writeOpaque500(w)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user