supabase-js icon indicating copy to clipboard operation
supabase-js copied to clipboard

GoTrueClient intercepts non-Supabase initiated OAuth preventing manual login flows

Open uncvrd opened this issue 1 year ago • 16 comments

Bug report

  • [ x] I confirm this is a bug with Supabase, not with my own application.
  • [ x] I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

Hi there, I've run in to an issue where Supabase Auth is intercepting url params/fragments that contain the keyword access_token in them even when auth requests aren't coming from a Supabase Auth initiated request.

For example, I use Supabase Auth for OAuth Login for social providers so I need to have detectSessionInUrl enabled. However, in my application I have a page for users to authenticate through Facebook Login to connect their Facebook Pages and Instagram Accounts.

I initiate this flow manually (outside of Supabase) using: https://developers.facebook.com/docs/instagram-platform/instagram-api-with-facebook-login/business-login-for-instagram

However the callback URL returns a string that looks like this:

https://my-clever-redirect-url.com/success/?#access_token=EAAHm...&data_access_expiration_time=1658889585&expires_in=4815&long_lived_token=ABAEs...

As you can see there is an access_token fragment. And if the user is logged in via Supabase already, this automatically logs the user out since it detects an access_token being returned in the URL, which is invalid and Supabase Auth uses this as a trigger to log the user out...

This issue occurs due to the check for implicitGrant here: https://github.com/supabase/auth-js/blob/8a1ec0602792191bd235d51fd45c0ec2cabdf216/src/GoTrueClient.ts#L311C31-L311C49

Where it checks if there are params for either (params.access_token || params.error_description)

Is there a way to prevent running this check on certain pages (like my redirect page) so there isn't this kind of conflict?

To prevent this, I thought I could just proxy my response through a server and rewrite the url to not interfere with Supabase but since this value is passed as a URL fragment, this data is not sent to a server and is only accessible in the browser...

Expected behavior

I expect to be able to use OAuth flow that isn't triggered by Supabase Auth without there being a conflict and Supabase intercepting non Supabase initiated Auth flows.

Screenshots

image

System information

  • OS: MacOS
  • Browser chrome
  • Version of supabase-js: 2.43.5
  • Version of Node.js: v20.12.0

uncvrd avatar Sep 24 '24 19:09 uncvrd

Related: https://github.com/supabase/supabase-js/issues/1704

j4w8n avatar Sep 26 '24 10:09 j4w8n

yea exactly, for now I've had to pnpm patch the GoTrue client to do this

image

uncvrd avatar Sep 30 '24 03:09 uncvrd

That was helpful, @uncvrd. I'm having the same issue so I created a patch. Will keep an eye here for any updates.

jgennari avatar Oct 20 '24 12:10 jgennari

Should be fixed in supabase/auth-js#986. I'm not sure when it'll get merged, but I believe it's close to being approved.

j4w8n avatar Mar 16 '25 11:03 j4w8n

Excited to see this land!

abeaclark avatar Apr 08 '25 00:04 abeaclark

Experiencing the same thing and thought I was going insane. I'm also hoping to see this fixed soon!

ben-katz avatar Apr 08 '25 17:04 ben-katz

@ben-katz as a short term fix I just stood up an interim api route to catch the callbacks and forward onto the destination as code_= instead of code= and then had my code prepared to watch for that param

abeaclark avatar Apr 09 '25 21:04 abeaclark

@mandarini hi there! reviewing the changes made in the associated PR, this unfortunately doesn't fix the issue presented in this ticket :/

I am running 2.87.1

On this line https://github.com/supabase/supabase-js/blob/13af49b21cde4e49ca5ebd7a77e933dc4d9747f8/packages/core/auth-js/src/GoTrueClient.ts#L467

there is a check to see if the url contains the correct params to be deemed something to act upon by the supabase auth library, unfortunately for OAuth flows like Facebook they return a hash with #access_token=xxyyzz (example in original post above) which still triggers the implicit auth flow in supabase auth and since this token is invalid for supabase, it causes my app to log users out.

Image

I can't proxy this response to a server endpoint since the access token is in a hash and these cannot be accessed server-side. Would you kindly re-open this ticket?

Thank you!

EDIT:

by doing this, I can fix it for now, but not ideal

    _isImplicitGrantCallback(params) {
        return Boolean(params.access_token || params.error_description) && !["/facebook/redirect"].includes(window.location.pathname);
    }

uncvrd avatar Dec 14 '25 03:12 uncvrd

Hi @uncvrd 💚 this looks like a mismatch 😢 between your client's flowType (pkce) and facebook returning implicit grant params. try setting detectSessionInUrl: false on your redirect route so you can handle the callback yourself. please let me know if this sorts it out

7ttp avatar Dec 14 '25 09:12 7ttp

hi @7ttp thanks for the quick response! In my original message I mentioned that I need detectSessionInUrl since I use Social OAuth providers for Supabase Login in the app. I just use a single client across the site that I import in to each file I need to make queries from....

export const supabase: SupaClient = createServerClient<Database>(serverEnv.VITE_SUPABASE_PROJECT_URL, serverEnv.VITE_SUPABASE_ANON_KEY, {
            cookies: {
                getAll() {
                    return Object.entries(getCookiesIsomorphicFn()).map(([name, value]) => ({
                        name,
                        value,
                    }))
                },
                setAll(cookies) {
                    cookies.forEach((cookie) => {
                        setCookieIsomorphicFn(cookie.name, cookie.value)
                    })
                },
            },
            cookieOptions: {
                domain: serverEnv.VITE_WEB_HOSTNAME,
            },
        })

Are you saying that I need a separate createServerClient with detectSessionInUrl disabled just for this route?

uncvrd avatar Dec 14 '25 09:12 uncvrd

@7ttp they aren't using Supabase OAuth for this flow, so the mismatch wouldn't apply.

@uncvrd the only thing I can think of is to switch your Supabase OAuth tactic to use the pkce mode. I'm not sure if that's viable for you or not.

j4w8n avatar Dec 14 '25 22:12 j4w8n

@j4w8n that's correct, this OAuth flow is independent from my general User Auth login flow handled nicely by Supabase.

Naive and general question to the audience, but is it possible for Supabase Auth to populate the callback URL with a Supabase Auth unique query param so that the library only acts upon such callbacks if a ?isSupabaseAuth=true&access_token=abc123 param exists or something?

This would ensure there wouldn't be any library conflict....just an idea

uncvrd avatar Dec 14 '25 22:12 uncvrd

Do you find that this issue needs to reopen?

mandarini avatar Dec 15 '25 19:12 mandarini

I believe it does

uncvrd avatar Dec 15 '25 19:12 uncvrd

Regarding your ask @uncvrd : yes, that seems feasible, if it's something the maintainers wanna do.

Make whatever change needed on the backend, then change the below function in auth-js to do an "and" check for that new param.

  /**
   * Checks if the current URL contains parameters given by an implicit oauth grant flow (https://www.rfc-editor.org/rfc/rfc6749.html#section-4.2)
   */
  private _isImplicitGrantCallback(params: { [parameter: string]: string }): boolean {
    return Boolean(params.access_token || params.error_description)
  }

j4w8n avatar Dec 15 '25 20:12 j4w8n

Reopened. Thanks for the detailed explanation @uncvrd and the input @j4w8n. To fix this properly, we need a server-side change in GoTrue to include a Supabase-specific identifier in the implicit grant redirect URL. Then we can update _isImplicitGrantCallback to check for that param. I'll discuss with the auth team to see if this is something we want to pursue. Will update here once I have more info.

mandarini avatar Dec 15 '25 20:12 mandarini