@@ -382,17 +382,14 @@ class GoTrueClient {
382382 /// If the ID token contains a `nonce` claim, then [nonce] must be
383383 /// provided to compare its hash with the value in the ID token.
384384 ///
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 ({
391387 required OAuthProvider provider,
392388 required String idToken,
393389 String ? accessToken,
394390 String ? nonce,
395391 String ? captchaToken,
392+ required bool linkIdentity,
396393 }) async {
397394 if (provider != OAuthProvider .google &&
398395 provider != OAuthProvider .apple &&
@@ -402,18 +399,24 @@ class GoTrueClient {
402399 '${OAuthProvider .google .name }, ${OAuthProvider .apple .name }, ${OAuthProvider .kakao .name } or ${OAuthProvider .keycloak .name }.' );
403400 }
404401
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+
405414 final response = await _fetch.request (
406415 '$_url /token' ,
407416 RequestMethodType .post,
408417 options: GotrueRequestOptions (
409418 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,
417420 query: {'grant_type' : 'id_token' },
418421 ),
419422 );
@@ -432,6 +435,28 @@ class GoTrueClient {
432435 return authResponse;
433436 }
434437
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+
435460 /// Log in a user using magiclink or a one-time password (OTP).
436461 ///
437462 /// If the `{{ .ConfirmationURL }}` variable is specified in the email template, a magiclink will be sent.
@@ -914,6 +939,38 @@ class GoTrueClient {
914939 return res.user? .identities ?? [];
915940 }
916941
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+
917974 /// Returns the URL to link the user's identity with an OAuth provider.
918975 Future <OAuthResponse > getLinkIdentityUrl (
919976 OAuthProvider provider, {
0 commit comments