From a9ea7caecb083d6cc96d341a12f82c41592b41dd Mon Sep 17 00:00:00 2001 From: Vinzent Date: Wed, 21 Jun 2023 22:12:29 +0200 Subject: [PATCH 1/7] feat(gotrue): add reauthenticate method --- packages/gotrue/lib/src/gotrue_client.dart | 24 ++++++++++++++++++- .../gotrue/lib/src/types/user_attributes.dart | 7 ++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/gotrue/lib/src/gotrue_client.dart b/packages/gotrue/lib/src/gotrue_client.dart index 611f19a4..764f2d80 100644 --- a/packages/gotrue/lib/src/gotrue_client.dart +++ b/packages/gotrue/lib/src/gotrue_client.dart @@ -479,8 +479,29 @@ class GoTrueClient { return refreshCompleter.future; } + /// Sends a reauthentication OTP to the user's email or phone number. + /// Requires the user to be signed-in. + Future reauthenticate() async { + final session = currentSession; + if (session == null) { + throw AuthException('Not logged in.'); + } + + final options = + GotrueRequestOptions(headers: headers, jwt: session.accessToken); + + await _fetch.request( + '$_url/reauthenticate', + RequestMethodType.get, + options: options, + ); + } + /// Updates user data, if there is a logged in user. - Future updateUser(UserAttributes attributes) async { + Future updateUser( + UserAttributes attributes, { + String? emailRedirectTo, + }) async { final accessToken = currentSession?.accessToken; if (accessToken == null) { throw AuthException('Not logged in.'); @@ -491,6 +512,7 @@ class GoTrueClient { headers: _headers, body: body, jwt: accessToken, + redirectTo: emailRedirectTo, ); final response = await _fetch.request('$_url/user', RequestMethodType.put, options: options); diff --git a/packages/gotrue/lib/src/types/user_attributes.dart b/packages/gotrue/lib/src/types/user_attributes.dart index 4e380b19..2a90ac8d 100644 --- a/packages/gotrue/lib/src/types/user_attributes.dart +++ b/packages/gotrue/lib/src/types/user_attributes.dart @@ -8,6 +8,11 @@ class UserAttributes { /// The user's password. String? password; + /// The nonce sent for reauthentication if the user's password is to be updated. + /// + /// Call reauthenticate() to obtain the nonce first. + String? nonce; + /// A custom data object to store the user's metadata. This maps to the `auth.users.user_metadata` column. /// /// The `data` should be a JSON object that includes user-specific info, such as their first and last name. @@ -17,6 +22,7 @@ class UserAttributes { this.email, this.phone, this.password, + this.nonce, this.data, }) : assert(data == null || data is List || data is Map); @@ -24,6 +30,7 @@ class UserAttributes { return { if (email != null) 'email': email, if (phone != null) 'phone': phone, + if (nonce != null) 'nonce': nonce, if (password != null) 'password': password, if (data != null) 'data': data, }; From f64a66dfb0f1cf70cdb9a10ca56268f671dc3812 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Thu, 22 Jun 2023 19:46:45 +0200 Subject: [PATCH 2/7] feat(gotrue): add resend method --- packages/gotrue/lib/src/gotrue_client.dart | 23 +++++++ packages/gotrue/lib/src/types/user.dart | 74 ++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/packages/gotrue/lib/src/gotrue_client.dart b/packages/gotrue/lib/src/gotrue_client.dart index 764f2d80..5f04b8a7 100644 --- a/packages/gotrue/lib/src/gotrue_client.dart +++ b/packages/gotrue/lib/src/gotrue_client.dart @@ -480,6 +480,7 @@ class GoTrueClient { } /// Sends a reauthentication OTP to the user's email or phone number. + /// /// Requires the user to be signed-in. Future reauthenticate() async { final session = currentSession; @@ -497,6 +498,28 @@ class GoTrueClient { ); } + ///Resends an existing signup confirmation email, email change email, SMS OTP or phone change OTP. + /// + ///Use [EmailResendParams] or [PhoneResendParams] to specify the type of resend. + Future resend(ResendParams params) async { + _removeSession(); + + final options = + GotrueRequestOptions(headers: headers, body: params.toJson()); + + final response = await _fetch.request( + '$_url/resend', + RequestMethodType.post, + options: options, + ); + + if ((response as Map).containsKey(['message_id'])) { + return ResendResponse(messageId: response['message_id']); + } else { + return ResendResponse(); + } + } + /// Updates user data, if there is a logged in user. Future updateUser( UserAttributes attributes, { diff --git a/packages/gotrue/lib/src/types/user.dart b/packages/gotrue/lib/src/types/user.dart index 1ad96a46..a63486b0 100644 --- a/packages/gotrue/lib/src/types/user.dart +++ b/packages/gotrue/lib/src/types/user.dart @@ -268,3 +268,77 @@ class UserIdentity { updatedAt.hashCode; } } + +class ResendResponse { + /// Only set for phone resend + String? messageId; + + ResendResponse({ + this.messageId, + }); +} + +abstract class ResendParams { + String? captchaToken; + Map toJson(); +} + +enum EmailResendType { + signup('signup'), + emailChange('email_change'); + + final String value; + + const EmailResendType(this.value); +} + +class EmailResendParams extends ResendParams { + EmailResendType type; + String email; + + EmailResendParams({ + required this.type, + required this.email, + }); + + @override + Map toJson() { + return { + 'type': type.name, + 'email': email, + 'gotrue_meta_security': { + 'captcha_token': captchaToken, + } + }; + } +} + +enum PhoneResendType { + sms('sms'), + phoneChange('phone_change'); + + final String value; + + const PhoneResendType(this.value); +} + +class PhoneResendParams extends ResendParams { + PhoneResendType type; + String phone; + + PhoneResendParams({ + required this.type, + required this.phone, + }); + + @override + Map toJson() { + return { + 'type': type.name, + 'phone': phone, + 'gotrue_meta_security': { + 'captcha_token': captchaToken, + } + }; + } +} From 4f65d4c75522041de317784034c2109fa567f098 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Thu, 22 Jun 2023 19:48:26 +0200 Subject: [PATCH 3/7] fix: use enum value --- packages/gotrue/lib/src/types/user.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gotrue/lib/src/types/user.dart b/packages/gotrue/lib/src/types/user.dart index a63486b0..fb3a23ab 100644 --- a/packages/gotrue/lib/src/types/user.dart +++ b/packages/gotrue/lib/src/types/user.dart @@ -304,7 +304,7 @@ class EmailResendParams extends ResendParams { @override Map toJson() { return { - 'type': type.name, + 'type': type.value, 'email': email, 'gotrue_meta_security': { 'captcha_token': captchaToken, @@ -334,7 +334,7 @@ class PhoneResendParams extends ResendParams { @override Map toJson() { return { - 'type': type.name, + 'type': type.value, 'phone': phone, 'gotrue_meta_security': { 'captcha_token': captchaToken, From 8cb75a72c4c1ce9a7324dfc0bb2ea988dbed63f0 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Thu, 29 Jun 2023 12:11:12 +0200 Subject: [PATCH 4/7] refactor: use name parameters --- packages/gotrue/lib/src/gotrue_client.dart | 23 +++++++- packages/gotrue/lib/src/types/user.dart | 65 ---------------------- 2 files changed, 20 insertions(+), 68 deletions(-) diff --git a/packages/gotrue/lib/src/gotrue_client.dart b/packages/gotrue/lib/src/gotrue_client.dart index 5f04b8a7..d43747e5 100644 --- a/packages/gotrue/lib/src/gotrue_client.dart +++ b/packages/gotrue/lib/src/gotrue_client.dart @@ -501,11 +501,28 @@ class GoTrueClient { ///Resends an existing signup confirmation email, email change email, SMS OTP or phone change OTP. /// ///Use [EmailResendParams] or [PhoneResendParams] to specify the type of resend. - Future resend(ResendParams params) async { + Future resend({ + String? email, + String? phone, + required OtpType type, + String? captchaToken, + }) async { + assert((email != null && phone == null) || (email == null && phone != null), + '`email` or `phone` needs to be specified.'); + _removeSession(); - final options = - GotrueRequestOptions(headers: headers, body: params.toJson()); + final body = { + if (email != null) 'email': email, + if (phone != null) 'phone': phone, + 'type': type.snakeCase, + 'gotrue_meta_security': {'captcha_token': captchaToken}, + }; + + final options = GotrueRequestOptions( + headers: _headers, + body: body, + ); final response = await _fetch.request( '$_url/resend', diff --git a/packages/gotrue/lib/src/types/user.dart b/packages/gotrue/lib/src/types/user.dart index fb3a23ab..320c0e33 100644 --- a/packages/gotrue/lib/src/types/user.dart +++ b/packages/gotrue/lib/src/types/user.dart @@ -277,68 +277,3 @@ class ResendResponse { this.messageId, }); } - -abstract class ResendParams { - String? captchaToken; - Map toJson(); -} - -enum EmailResendType { - signup('signup'), - emailChange('email_change'); - - final String value; - - const EmailResendType(this.value); -} - -class EmailResendParams extends ResendParams { - EmailResendType type; - String email; - - EmailResendParams({ - required this.type, - required this.email, - }); - - @override - Map toJson() { - return { - 'type': type.value, - 'email': email, - 'gotrue_meta_security': { - 'captcha_token': captchaToken, - } - }; - } -} - -enum PhoneResendType { - sms('sms'), - phoneChange('phone_change'); - - final String value; - - const PhoneResendType(this.value); -} - -class PhoneResendParams extends ResendParams { - PhoneResendType type; - String phone; - - PhoneResendParams({ - required this.type, - required this.phone, - }); - - @override - Map toJson() { - return { - 'type': type.value, - 'phone': phone, - 'gotrue_meta_security': { - 'captcha_token': captchaToken, - } - }; - } -} From 84a42432b8cf13fdc0e8d133f010ecaf5b3b0335 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Fri, 30 Jun 2023 13:11:29 +0200 Subject: [PATCH 5/7] Update packages/gotrue/lib/src/gotrue_client.dart --- packages/gotrue/lib/src/gotrue_client.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/gotrue/lib/src/gotrue_client.dart b/packages/gotrue/lib/src/gotrue_client.dart index d43747e5..2c371e04 100644 --- a/packages/gotrue/lib/src/gotrue_client.dart +++ b/packages/gotrue/lib/src/gotrue_client.dart @@ -510,7 +510,9 @@ class GoTrueClient { assert((email != null && phone == null) || (email == null && phone != null), '`email` or `phone` needs to be specified.'); - _removeSession(); + if (type != OtpType.emailChange && type != OtpType.phoneChange) { + _removeSession(); + } final body = { if (email != null) 'email': email, From fdfe6424c4779bdf703386c92f7bb2c57c9695ca Mon Sep 17 00:00:00 2001 From: Vinzent Date: Fri, 30 Jun 2023 17:52:35 +0200 Subject: [PATCH 6/7] refactor: move ResendResponse to auth_response.dart --- packages/gotrue/lib/src/types/auth_response.dart | 9 +++++++++ packages/gotrue/lib/src/types/user.dart | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/gotrue/lib/src/types/auth_response.dart b/packages/gotrue/lib/src/types/auth_response.dart index 1bed44fc..724b9bc5 100644 --- a/packages/gotrue/lib/src/types/auth_response.dart +++ b/packages/gotrue/lib/src/types/auth_response.dart @@ -36,6 +36,15 @@ class UserResponse { UserResponse.fromJson(Map json) : user = User.fromJson(json); } +class ResendResponse { + /// Only set for phone resend + String? messageId; + + ResendResponse({ + this.messageId, + }); +} + class AuthSessionUrlResponse { final Session session; final String? redirectType; diff --git a/packages/gotrue/lib/src/types/user.dart b/packages/gotrue/lib/src/types/user.dart index 320c0e33..1ad96a46 100644 --- a/packages/gotrue/lib/src/types/user.dart +++ b/packages/gotrue/lib/src/types/user.dart @@ -268,12 +268,3 @@ class UserIdentity { updatedAt.hashCode; } } - -class ResendResponse { - /// Only set for phone resend - String? messageId; - - ResendResponse({ - this.messageId, - }); -} From 2eb62694ea70c9dba1750d42ee206573297fd795 Mon Sep 17 00:00:00 2001 From: Vinzent Date: Thu, 6 Jul 2023 19:41:04 +0200 Subject: [PATCH 7/7] fix: add emailRedirectTo to resend --- packages/gotrue/lib/src/gotrue_client.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/gotrue/lib/src/gotrue_client.dart b/packages/gotrue/lib/src/gotrue_client.dart index 2c371e04..67f6c0f2 100644 --- a/packages/gotrue/lib/src/gotrue_client.dart +++ b/packages/gotrue/lib/src/gotrue_client.dart @@ -505,6 +505,7 @@ class GoTrueClient { String? email, String? phone, required OtpType type, + String? emailRedirectTo, String? captchaToken, }) async { assert((email != null && phone == null) || (email == null && phone != null), @@ -524,6 +525,7 @@ class GoTrueClient { final options = GotrueRequestOptions( headers: _headers, body: body, + redirectTo: emailRedirectTo, ); final response = await _fetch.request(