Skip to content

Commit 0719e55

Browse files
authored
fix(auth): fix verifyOTP parameter validation for OtpType.recovery with tokenHash (#1295)
fix(auth): token hash verification
1 parent 0d68e50 commit 0719e55

File tree

2 files changed

+55
-9
lines changed

2 files changed

+55
-9
lines changed

packages/gotrue/lib/src/gotrue_client.dart

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -518,17 +518,28 @@ class GoTrueClient {
518518
String? captchaToken,
519519
String? tokenHash,
520520
}) async {
521-
assert(
522-
((email != null && phone == null) ||
523-
(email == null && phone != null)) ||
524-
(tokenHash != null),
525-
'`email` or `phone` needs to be specified.');
526-
assert(token != null || tokenHash != null,
527-
'`token` or `tokenHash` needs to be specified.');
521+
// For recovery type with tokenHash, only tokenHash and type are required
522+
final isRecoveryWithTokenHash =
523+
type == OtpType.recovery && tokenHash != null;
524+
525+
if (!isRecoveryWithTokenHash) {
526+
assert(
527+
((email != null && phone == null) ||
528+
(email == null && phone != null)) ||
529+
(tokenHash != null),
530+
'`email` or `phone` needs to be specified.');
531+
assert(token != null || tokenHash != null,
532+
'`token` or `tokenHash` needs to be specified.');
533+
} else {
534+
// For recovery with tokenHash, email/phone should not be provided
535+
assert(email == null && phone == null,
536+
'For recovery type with tokenHash, only tokenHash and type should be provided.');
537+
}
528538

529539
final body = {
530-
if (email != null) 'email': email,
531-
if (phone != null) 'phone': phone,
540+
// For recovery type with tokenHash, exclude email/phone
541+
if (!isRecoveryWithTokenHash && email != null) 'email': email,
542+
if (!isRecoveryWithTokenHash && phone != null) 'phone': phone,
532543
if (token != null) 'token': token,
533544
'type': type.snakeCase,
534545
'redirect_to': redirectTo,

packages/gotrue/test/otp_mock_test.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,41 @@ void main() {
130130
expect(client.currentUser, isNotNull);
131131
});
132132

133+
test('verifyOTP() with recovery type and tokenHash', () async {
134+
// Recovery type with tokenHash should only include tokenHash and type
135+
final response = await client.verifyOTP(
136+
tokenHash: 'mock-token-hash',
137+
type: OtpType.recovery,
138+
);
139+
140+
expect(response.session, isNotNull);
141+
expect(response.user, isNotNull);
142+
143+
// Verify session was set
144+
expect(client.currentSession, isNotNull);
145+
expect(client.currentUser, isNotNull);
146+
});
147+
148+
test(
149+
'verifyOTP() with recovery type and tokenHash should reject email/phone',
150+
() async {
151+
// Recovery type with tokenHash should not accept email/phone
152+
try {
153+
await client.verifyOTP(
154+
email: testEmail,
155+
tokenHash: 'mock-token-hash',
156+
type: OtpType.recovery,
157+
);
158+
fail('Should have thrown an assertion error');
159+
} catch (e) {
160+
expect(e, isA<AssertionError>());
161+
expect(
162+
e.toString(),
163+
contains(
164+
'For recovery type with tokenHash, only tokenHash and type should be provided'));
165+
}
166+
});
167+
133168
test('verifyOTP() without token should throw', () async {
134169
try {
135170
await client.verifyOTP(

0 commit comments

Comments
 (0)