Skip to content

Commit 7f88985

Browse files
cstocktonoelmgrenChris Stockton
authored
fix: exempt PKCE recovery sessions from require-current-password check (#2502)
This change fixes a unit test and uses gofmt on top of pr #2497. --------- Co-authored-by: Ollie Elmgren <ollie@listenlabs.ai> Co-authored-by: Chris Stockton <chris.stockton@supabase.io>
1 parent bb521e4 commit 7f88985

4 files changed

Lines changed: 33 additions & 12 deletions

File tree

internal/api/user.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,8 @@ func (a *API) UserUpdate(w http.ResponseWriter, r *http.Request) error {
168168
if user.HasPassword() {
169169
// current password required when updating password
170170
if config.Security.UpdatePasswordRequireCurrentPassword {
171-
// user may be in a password reset flow, where they do not have a currentPassword
172-
isRecoverySession := false
173-
for _, claim := range session.AMRClaims {
174-
// password recovery flows can be via otp or a magic link, check if the current session
175-
// was created with one of those
176-
if claim.GetAuthenticationMethod() == "otp" || claim.GetAuthenticationMethod() == "magiclink" {
177-
isRecoverySession = true
178-
break
179-
}
180-
}
181-
if !isRecoverySession {
171+
// ensure user is not in a password recovery flow
172+
if !session.IsRecovery() {
182173
if params.CurrentPassword == nil || *params.CurrentPassword == "" {
183174
return apierrors.NewBadRequestError(apierrors.ErrorCodeCurrentPasswordRequired, "Current password required when setting new password.")
184175
}

internal/api/user_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,17 @@ func (ts *UserTestSuite) TestUserUpdatePasswordViaRecovery() {
434434
recoveryType: models.MagicLink,
435435
expected: expected{code: http.StatusOK, isAuthenticated: true},
436436
},
437+
{
438+
desc: "Current password not required in PKCE recovery flow",
439+
newPassword: "newpassword789",
440+
recoveryType: models.Recovery,
441+
expected: expected{code: http.StatusOK, isAuthenticated: true},
442+
},
437443
{
438444
desc: "Current password required for any other claim",
439445
newPassword: "newpassword456",
440446
recoveryType: models.EmailChange,
441-
expected: expected{code: http.StatusBadRequest, isAuthenticated: true},
447+
expected: expected{code: http.StatusBadRequest, isAuthenticated: false},
442448
},
443449
}
444450

internal/models/factor.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ const (
5959
PasskeyLogin
6060
)
6161

62+
func (authMethod AuthenticationMethod) IsRecovery() bool {
63+
switch authMethod {
64+
case OTP, MagicLink, Recovery:
65+
return true
66+
default:
67+
return false
68+
}
69+
}
70+
6271
func (authMethod AuthenticationMethod) String() string {
6372
switch authMethod {
6473
case OAuth:

internal/models/sessions.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,21 @@ func (Session) TableName() string {
105105
return tableName
106106
}
107107

108+
func (s *Session) IsRecovery() bool {
109+
for _, claim := range s.AMRClaims {
110+
amStr := claim.GetAuthenticationMethod()
111+
am, err := ParseAuthenticationMethod(amStr)
112+
if err != nil {
113+
// We want to assert this is a recovery session, skip invalid.
114+
continue
115+
}
116+
if am.IsRecovery() {
117+
return true
118+
}
119+
}
120+
return false
121+
}
122+
108123
func (s *Session) GetRefreshTokenHmacKey(dbEncryption conf.DatabaseEncryptionConfiguration) ([]byte, bool, error) {
109124
if s.RefreshTokenHmacKey == nil {
110125
return nil, false, nil

0 commit comments

Comments
 (0)