auth-module icon indicating copy to clipboard operation
auth-module copied to clipboard

OAuth2 Logout - `logoutRedirectUri` does not work correctly

Open franck-grenier opened this issue 3 years ago • 4 comments

Version

module: 5.0.0-1648802546.c9880dc nuxt: 2.15.8

Nuxt configuration

mode:

  • [x] universal

Nuxt configuration

auth: {
        cookie: {
            options: {
                expires: 365,
                secure: process.env.APP_ENV !== 'local',
            },
        },
        strategies: {
            idp: {
                scheme: 'oauth2',
                endpoints: {
                    authorization: process.env.OAUTH_AUTHORIZE_URL,
                    token: process.env.OAUTH_TOKEN_URL,
                    userInfo: process.env.OAUTH_USER_URL,
                    logout: process.env.OAUTH_LOGOUT_URL,
                },
                clientId: process.env.OAUTH_CLIENT_ID,
                token: {
                    property: 'access_token',
                    type: 'Bearer',
                    maxAge: 1800,
                },
                refreshToken: {
                    property: 'refresh_token',
                    maxAge: 60 * 60 * 24 * 30,
                },
                responseType: 'code',
                grantType: 'authorization_code',
                redirectUri: process.env.OAUTH_CALLBACK_URL,
                logoutRedirectUri: process.env.OAUTH_REDIRECT_AFTER_LOGOUT_URL,
                codeChallengeMethod: 'plain',
                autoFetchUser: false,
                autoLogout: true,
            },
        },
        plugins: [
            '~/plugins/updateLoggedInUser.js',
        ],
    },
}

Reproduction

What is expected?

I expect logout to do 3 actions :

  1. GET request on my OAuth2 logout endpoint which logs user out from my auth server and answers 302 to logoutRedirectUri :white_check_mark:
  2. logout user from my front Nuxt app :white_check_mark:
  3. Redirect my user to logoutRedirectUri after logout :stop_sign:

The strange behaviour is that if I logout from homepage (/), redirection to logoutRedirectUr works. But not from any other pages.

What is actually happening?

The GET request on my logout auth server endpoint is sent but immediately cancelled on client side and ends in 499 on server side (Nginx). The logout is effective on the auth server. But Nuxt does not get any answer and does not redirect user to logoutRedirectUri.

Additional information

I'm not sure about what my OAuth2 logout endpoint should do according to Nuxt Auth. Does it need to answer 200 or 302 to logoutRedirectUri ? What could cancel the GET request on Nuxt side ?

Thanks for your help

Checklist

  • [x] I have tested with the latest Nuxt version and the issue still occurs
  • [x] I have tested with the latest module version and the issue still occurs
  • [x] I have searched the issue tracker and this issue hasn't been reported yet

franck-grenier avatar Sep 05 '22 08:09 franck-grenier

Having the exact same problem here, anybody has an answer ?

drayanqi avatar Oct 17 '22 16:10 drayanqi

I found the faulty code: https://github.com/nuxt-community/auth-module/blob/dev/src/schemes/oauth2.ts#L320

logout(): void {
  if (this.options.endpoints.logout) {
    const opts = {
      client_id: this.options.clientId + '',
      logout_uri: this.logoutRedirectURI
    }
    const url = this.options.endpoints.logout + '?' + encodeQuery(opts)
    window.location.replace(url)
  }
  return this.$auth.reset() // <---- this seems to stop the upper "window.location.replace(url)"
}

As logout endpoint is optional and reset() function does not return anything, I'd rather go with something like that:

logout() {
  this.$auth.reset();
  if (this.options.endpoints.logout) {
    const opts = {
      client_id: this.options.clientId + "",
      logout_uri: this.logoutRedirectURI
    };
    const url = this.options.endpoints.logout + "?" + encodeQuery(opts);
    window.location.replace(url);
  }
}

I'm also investigating around a resetInterceptor which seems to send Axios requests on reset.

franck-grenier avatar Oct 18 '22 07:10 franck-grenier

More details on this problem.

In the reset() method, this.$auth.setUser(false); is faulty :

reset() {
  this.$auth.setUser(false); // <---- this stops the upper "window.location.replace(url)"
  this.token.reset();
  this.refreshToken.reset();
  this.requestHandler.reset();
}

this.$auth.setUser(false); sometimes redirects to /login before getting the response of window.location.replace(url);.

franck-grenier avatar Oct 27 '22 10:10 franck-grenier

Ok, looks like we found a solution.

It's a "race condition" problem between 2 navigation instructions :

  • logout on OAuth server (window.location.replace(url);)
  • logout on Nuxt (this.$auth.reset())

Disabling the option watchLoggedIn (https://auth.nuxtjs.org/api/options/#watchloggedin) solved the problem as it disabled auto-redirection to /login on this.$auth.setUser(false);.

Interesting topic about browsers behaviour : https://stackoverflow.com/questions/2536793/does-changing-window-location-stop-execution-of-javascript

However, I think Nuxt Auth logout functions should handle that point natively.

franck-grenier avatar Oct 28 '22 09:10 franck-grenier