@@ -382,17 +382,14 @@ class GoTrueClient {
382
382
/// If the ID token contains a `nonce` claim, then [nonce] must be
383
383
/// provided to compare its hash with the value in the ID token.
384
384
///
385
- /// [captchaToken] is the verification token received when the user
386
- /// completes the captcha on the app.
387
- ///
388
- /// This method is experimental.
389
- @experimental
390
- Future <AuthResponse > signInWithIdToken ({
385
+ /// Sign in with ID token (internal helper method).
386
+ Future <AuthResponse > _signInWithIdToken ({
391
387
required OAuthProvider provider,
392
388
required String idToken,
393
389
String ? accessToken,
394
390
String ? nonce,
395
391
String ? captchaToken,
392
+ required bool linkIdentity,
396
393
}) async {
397
394
if (provider != OAuthProvider .google &&
398
395
provider != OAuthProvider .apple &&
@@ -402,18 +399,24 @@ class GoTrueClient {
402
399
'${OAuthProvider .google .name }, ${OAuthProvider .apple .name }, ${OAuthProvider .kakao .name } or ${OAuthProvider .keycloak .name }.' );
403
400
}
404
401
402
+ final body = {
403
+ 'provider' : provider.snakeCase,
404
+ 'id_token' : idToken,
405
+ 'nonce' : nonce,
406
+ 'gotrue_meta_security' : {'captcha_token' : captchaToken},
407
+ 'access_token' : accessToken,
408
+ };
409
+
410
+ if (linkIdentity) {
411
+ body['link_identity' ] = true ;
412
+ }
413
+
405
414
final response = await _fetch.request (
406
415
'$_url /token' ,
407
416
RequestMethodType .post,
408
417
options: GotrueRequestOptions (
409
418
headers: _headers,
410
- body: {
411
- 'provider' : provider.snakeCase,
412
- 'id_token' : idToken,
413
- 'nonce' : nonce,
414
- 'gotrue_meta_security' : {'captcha_token' : captchaToken},
415
- 'access_token' : accessToken,
416
- },
419
+ body: body,
417
420
query: {'grant_type' : 'id_token' },
418
421
),
419
422
);
@@ -432,6 +435,28 @@ class GoTrueClient {
432
435
return authResponse;
433
436
}
434
437
438
+ /// [captchaToken] is the verification token received when the user
439
+ /// completes the captcha on the app.
440
+ ///
441
+ /// This method is experimental.
442
+ @experimental
443
+ Future <AuthResponse > signInWithIdToken ({
444
+ required OAuthProvider provider,
445
+ required String idToken,
446
+ String ? accessToken,
447
+ String ? nonce,
448
+ String ? captchaToken,
449
+ }) async {
450
+ return _signInWithIdToken (
451
+ provider: provider,
452
+ idToken: idToken,
453
+ accessToken: accessToken,
454
+ nonce: nonce,
455
+ captchaToken: captchaToken,
456
+ linkIdentity: false ,
457
+ );
458
+ }
459
+
435
460
/// Log in a user using magiclink or a one-time password (OTP).
436
461
///
437
462
/// If the `{{ .ConfirmationURL }}` variable is specified in the email template, a magiclink will be sent.
@@ -914,6 +939,38 @@ class GoTrueClient {
914
939
return res.user? .identities ?? [];
915
940
}
916
941
942
+ /// Link an identity to the current user using an ID token.
943
+ ///
944
+ /// [provider] is the OAuth provider (google, apple, kakao, or keycloak)
945
+ ///
946
+ /// [idToken] is the ID token from the OAuth provider
947
+ ///
948
+ /// [accessToken] is the access token from the OAuth provider
949
+ ///
950
+ /// [nonce] is the nonce used for the OAuth flow
951
+ ///
952
+ /// [captchaToken] is the verification token received when the user
953
+ /// completes the captcha on the app.
954
+ ///
955
+ /// This method is experimental.
956
+ @experimental
957
+ Future <AuthResponse > linkIdentityWithIdToken ({
958
+ required OAuthProvider provider,
959
+ required String idToken,
960
+ String ? accessToken,
961
+ String ? nonce,
962
+ String ? captchaToken,
963
+ }) async {
964
+ return _signInWithIdToken (
965
+ provider: provider,
966
+ idToken: idToken,
967
+ accessToken: accessToken,
968
+ nonce: nonce,
969
+ captchaToken: captchaToken,
970
+ linkIdentity: true ,
971
+ );
972
+ }
973
+
917
974
/// Returns the URL to link the user's identity with an OAuth provider.
918
975
Future <OAuthResponse > getLinkIdentityUrl (
919
976
OAuthProvider provider, {
0 commit comments