supabase / auth-js

An isomorphic Javascript library for Supabase Auth.
MIT License
321 stars 153 forks source link

Using a non-Supabase OAuth implicit grant flow for non-login purposes logs the user out #758

Closed kav closed 11 months ago

kav commented 11 months ago

We're running into https://github.com/supabase/gotrue-js/issues/527 but it was closed incorrectly as @hf seemed to not fully grok the issue. In fact their comment:

If you need to use OAuth in your app for other purposes (to re-authorize or ask for a bigger scope -- to read a user's contacts for example) you should implement this within your app.

Is exactly what fails due to the issue. You can not implement an implicit grant oauth request within your application without go-true hijacking the returning request and assuming it's a supabase login.

Say for example my application uses supabase for auth but somewhere in my app I use an implicit grant flow to get access to a user's data on a third party site, not a supabase auth provider, just another site that uses implicit oauth grants to access data. gotrue-js hijacks the callback because it thinks it's seeing a incoming supabase grant when in fact it's seeing the third party grant. This not only blocks finishing the third-party grant it wipes the current supabase session.

Original issue details below.

Bug report

Describe the bug

If a site using Supabase Auth uses an OAuth implicit grant flow for reasons other than managing user accounts (e.g., fetching data from a third party website), then upon redirect, GoTrueClient will automatically detect the #access_token fragment, and attempt create a session using that token.

This token, naturally, cannot be used for Supabase authentication. The resulting error causes any existing user session to be removed.

To Reproduce

  1. Go to supabase.com, and log in to your user account.
  2. Append #access_token=anystring to the URL, and reload the page.
  3. Observe that you have been logged out.

This can also be demonstrated in a fresh project such as https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management

Any OAuth grant flow that places an unrecognized #access_token in the URL will also log out the user, whether it was intended to or not.

Expected behavior

The user remains logged in during OAuth flows unrelated to user account management. Failing that, the app clearly communicates that

  1. A user login process has been initiated due to URL contents.
  2. The login process failed due to an invalid access token.

System information

Reproduced in supabase-js 1 and 2, with gotrue-js 1.24 and 2.2.2.

Additional context

I'm a dummy, so for all I know this is a feature request rather than a bug report, but it drove me crazy for a hot minute until I figured it out.

Workaround/fix:

I fixed this for myself by patching GoTrueClient's _isImplicitGrantFlow method to check for a custom flag in the state argument that I give to the OAuth provider, preventing _getSessionFromUrl from triggering unintentionally.

_isImplicitGrantFlow() {
        return (isBrowser() &&
            (Boolean(getParameterByName('access_token')) ||
                Boolean(getParameterByName('error_description')))
                && Boolean(!getParameterByName('state')?.startsWith('nogrant')));
    }

Another solution might involve a client option to designate a URL path where GoTrueClient will ignore #access_tokens, and using that path in the OAuth redirect for non-login OAuth providers.

hf commented 11 months ago

Is exactly what fails due to the issue. You can not implement an implicit grant oauth request within your application without go-true hijacking the returning request and assuming it's a supabase login.

I see, this makes some sense. I'll see what we can do about this in future major versions. There's no way for us to change the behavior now without breaking backward compatibility. Until then, you can use the detectSessionInUrl option, which when set to false won't pick up the implicit flow parameters from the OAuth redirect back to your application.

For example, if the OAuth redirect takes the user back to /oauth-callback on your application, you can initialize GoTrueClient like so:

new GoTrueClient({
  detectSessionInUrl: window.location.pathname !== "/oauth-callback"
})

Or, when using supabase-js, something like:

createClient('...', '...', {
  auth: {
    detectSessionInUrl: window.location.pathname !== "/oauth-callback"
  }
})

I'll close this as won't fix but will be addressed in v3.