From 9231ae077c724eaf6763d721ee7a4e6fdfd24e78 Mon Sep 17 00:00:00 2001 From: Samarth Kolanupaka Date: Tue, 27 Jan 2026 22:51:01 -0500 Subject: [PATCH 1/3] fix(auth): detect provider-only link callback --- packages/core/auth-js/src/GoTrueClient.ts | 27 ++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 4de54bd57..b69e221a7 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -2052,6 +2052,26 @@ export default class GoTrueClient { } = params if (!access_token || !expires_in || !refresh_token || !token_type) { + if (provider_token || provider_refresh_token) { + const { data: sessionData, error: sessionError } = await this.__loadSession() + if (sessionError) throw sessionError + if (!sessionData.session) { + throw new AuthImplicitGrantRedirectError('No session defined in URL') + } + + const session: Session = { + ...sessionData.session, + provider_token, + provider_refresh_token, + } + + // Remove tokens from URL + window.location.hash = '' + this._debug('#_getSessionFromURL()', 'clearing window.location.hash') + + return this._returnResult({ data: { session, redirectType: params.type }, error: null }) + } + throw new AuthImplicitGrantRedirectError('No session defined in URL') } @@ -2126,7 +2146,12 @@ export default class GoTrueClient { if (typeof this.detectSessionInUrl === 'function') { return this.detectSessionInUrl(new URL(window.location.href), params) } - return Boolean(params.access_token || params.error_description) + return Boolean( + params.access_token || + params.error_description || + params.provider_token || + params.provider_refresh_token + ) } /** From 0a1649d8c606c8d16a57780b32cfcc34118a201e Mon Sep 17 00:00:00 2001 From: Samarth Kolanupaka Date: Tue, 27 Jan 2026 22:53:54 -0500 Subject: [PATCH 2/3] test(auth): cover provider-token-only link callback --- .../auth-js/test/GoTrueClient.browser.test.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/core/auth-js/test/GoTrueClient.browser.test.ts b/packages/core/auth-js/test/GoTrueClient.browser.test.ts index b0b0a15d9..2214c6b57 100644 --- a/packages/core/auth-js/test/GoTrueClient.browser.test.ts +++ b/packages/core/auth-js/test/GoTrueClient.browser.test.ts @@ -346,6 +346,32 @@ describe('Callback URL handling', () => { expect(session?.refresh_token).toBe('test-refresh-token') }) + it('should attach provider token when callback only includes provider tokens', async () => { + window.location.href = + 'http://localhost:9999/callback#provider_token=provider-token&provider_refresh_token=provider-refresh&type=link' + + const expiresAt = Math.floor(Date.now() / 1000) + 3600 + storedSession = JSON.stringify({ + access_token: 'existing-access-token', + refresh_token: 'existing-refresh-token', + expires_in: 3600, + expires_at: expiresAt, + token_type: 'bearer', + user: { id: 'test-user' }, + }) + + const client = getClientWithSpecificStorage(mockStorage) + await client.initialize() + + const { + data: { session }, + } = await client.getSession() + expect(session).toBeDefined() + expect(session?.access_token).toBe('existing-access-token') + expect(session?.provider_token).toBe('provider-token') + expect(session?.provider_refresh_token).toBe('provider-refresh') + }) + it('should handle error in callback URL', async () => { // Set up URL with error parameters window.location.href = From c30e189174e236edd3ffa15ca8c18174d7108c13 Mon Sep 17 00:00:00 2001 From: Samarth Kolanupaka Date: Tue, 27 Jan 2026 23:13:32 -0500 Subject: [PATCH 3/3] fix(auth): use _useSession for provider-only callbacks --- packages/core/auth-js/src/GoTrueClient.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index b69e221a7..befc79cb3 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -2053,7 +2053,9 @@ export default class GoTrueClient { if (!access_token || !expires_in || !refresh_token || !token_type) { if (provider_token || provider_refresh_token) { - const { data: sessionData, error: sessionError } = await this.__loadSession() + const { data: sessionData, error: sessionError } = await this._useSession( + async (result) => result + ) if (sessionError) throw sessionError if (!sessionData.session) { throw new AuthImplicitGrantRedirectError('No session defined in URL')