Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh should redirect to login page on fail #289

Closed
jap1968 opened this issue Nov 14, 2017 · 35 comments
Closed

Refresh should redirect to login page on fail #289

jap1968 opened this issue Nov 14, 2017 · 35 comments

Comments

@jap1968
Copy link

jap1968 commented Nov 14, 2017

Under some circumstances, the token in the browser can expire, so there is not possible anymore to refresh it. The call to the refresh method on the API will return a 401 (unauthorized) code.

In these cases, the application should either logout (to clear the current non-valid token) or redirect again to the login page.

Currently, the application gets hung on pages requiring authorization if the token has already expired. The only solution (that I have found so far) is to clear the local storage in the browser in order to be able to authenticate again.

@jap1968
Copy link
Author

jap1968 commented Nov 14, 2017

What about doing something like this?

line 72@auth.js

if (this.options.refreshData.enabled && this.options.tokenExpired.call(this)) {
    this.options.refreshPerform.call(this, {
        success: function () {
            this.options.checkAuthenticated.call(_this, cb);
        },
        error: function () {
            this.options.logoutProcess.call(this, null, {});        
        }
    });
    return;
}

@websanova
Copy link
Owner

websanova commented Nov 14, 2017 via email

@jap1968
Copy link
Author

jap1968 commented Nov 15, 2017

Just created a new project (as a proof of concept) with the minimal required components using the current software versions:

    "@websanova/vue-auth": "^2.20.4-beta",
    "vue": "^2.5.2",
    "vue-axios": "^2.0.2",
    "vue-router": "^3.0.1"
    "vue-loader": "^13.3.0",

$ npm -v
5.5.1

@websanova
Copy link
Owner

websanova commented Nov 15, 2017 via email

@jap1968
Copy link
Author

jap1968 commented Nov 15, 2017

In order to test this issue, I am generating a deliberately short-living JWT token, with an expiration time of 180 seconds. Token generation is ok, and manual refresh is OK, too.

The vue application seems to ignore the expiration time of the token. Instead, it seems to be trying to refresh at some given instants (hardcoded, maybe?), not related to the expiration claim in the token.

So, the result is the application trying to refresh the token too late, when the token has already expired, and the refreshing request is rejected with a 401 error code.

@websanova
Copy link
Owner

websanova commented Nov 15, 2017 via email

@jap1968
Copy link
Author

jap1968 commented Nov 15, 2017

After the token expiration, when I try to access any route requiring authentification, the application, first of all, tries to refresh the token. This refresh operation fails (401) and the application just stops, so it does not perform a logout. The application gets hung with the auth component in a non-ready state. I mean it shows the loading... text:

<div v-if="!$auth.ready()">
Loading ...
</div>

refresh-401

@jap1968
Copy link
Author

jap1968 commented Nov 15, 2017

vue-auth tries to refresh the token every 30 min, independently of the expiration claim contained in the token. The software should consider the posibility of not being successful in the refresh operation, assuming in such case that the user has been logged out from the application.

What I can see in the logs of the API who provides the initial JWT tokens as well as the refresh tokens is this (real token contents has been shortened). Notice the 30 min time between requests, even when the expiration time claim for our JWT tokens is just 180 s:

[2017-11-15 11:26:21] slim-app.WARNING: Expired token ["eyJ0eXAi...Iq8"] {"uid":"22c0302"}
[2017-11-15 11:56:21] slim-app.WARNING: Expired token ["eyJ0eXAi...Iq8"] {"uid":"304ce45"}
[2017-11-15 12:26:21] slim-app.WARNING: Expired token ["eyJ0eXAi...lq8"] {"uid":"3073f2b"}
[2017-11-15 12:56:21] slim-app.WARNING: Expired token ["eyJ0eXAi...Iq8"] {"uid":"b30ac8b"}

@websanova
Copy link
Owner

websanova commented Nov 15, 2017 via email

@jap1968
Copy link
Author

jap1968 commented Nov 16, 2017

I am not sure about interceptors setup. I am rather new to vue.js and I still have a lot of doubts about it. This is what I have in the main.js file:

import Vue from 'vue'
import App from './App'
import router from './router'

import axios from 'axios'
import VueAxios from 'vue-axios'

Vue.use(VueAxios, axios)
Vue.axios.defaults.baseURL = 'http://10.36.156.154:8089/api/v1/'

Vue.router = router

// Token refresh disabled ATM
// https://github.com/websanova/vue-auth/issues/289
// https://stackoverflow.com/a/39897838
Vue.use(require('@websanova/vue-auth'), {
  auth: require('@websanova/vue-auth/drivers/auth/bearer.js'),
  http: require('@websanova/vue-auth/drivers/http/axios.1.x.js'),
  router: require('@websanova/vue-auth/drivers/router/vue-router.2.x.js'),
  tokenExpired: () => {
    return false
  }
})

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

@websanova
Copy link
Owner

websanova commented Nov 16, 2017 via email

@jap1968
Copy link
Author

jap1968 commented Nov 16, 2017

I added this method just a few hours ago according to the solution to a similar question from stackoverflow:
VueJS (resource, router and @websanova/vue-auth) login with JWT tokens refresh token error

Without this method, the application hangs when tokens expire. With this method, the application does not call the refresh method, but at least, the user gets logged out and redirected to the login form.

@websanova
Copy link
Owner

websanova commented Nov 16, 2017 via email

@jap1968
Copy link
Author

jap1968 commented Nov 20, 2017

I am experiencing this same problem even with your demo sample out of the box.
Downloaded the sample as of today. Changed just the API endpoint to connect with our test API. The sample does not use axios, but just vue-resource.

If the endpoint API provides a token with an expiration time under the preset 30 minutes, the refresh operation fails. Any subsequent operation fails too (as trying to get auth/user) but the user is not logged out. Screenshot attached.

captura de pantalla de 2017-11-20 09-16-09

You can recreate the problem using your Laravel API. Just configure the tokens to have an expiration time under 30 minutes. In the first refresh you will see the problem.

@websanova
Copy link
Owner

Ok,

Well I found one issue where the refresh was still running even after a logout (with the refresh interval). So that should be fixed now in v2.20.8-beta.

But why you aren't being logged out on a 401 response is a bit strange. Can you double check everything you have running locally is latest? Is the demo you are running a fresh install?

@jap1968
Copy link
Author

jap1968 commented Nov 23, 2017

Just tested everything with v2.20.8-beta. The problem of the requests for refresh tokens after logout (and before login) is now fixed, but the logout problem persists. I will keep doing some additional tests.

@jap1968
Copy link
Author

jap1968 commented Nov 29, 2017

Tested again with v2.20.9-beta. Same problem. Refresh token error should remove the default_auth_token local storage. Otherwise, users do no log out properly.

Our scenario: An employee logs into the corporate intranet. After finished working, many of them do not logout properly, but just close the browser tab. So, the frontend is unable to keep refreshing the token, and after a given period of time the token is not valid anymore. After a while (maybe several hours later) another different employee tries to log into the corporate intranet using the same computer. We do not want the browser to refresh the previous token (belonging to another user, and already expired). What we want is just to redirect the user to the website login page.

@peluprvi
Copy link

@jap1968 by your description, maybe you want to logout the user as soon as it closes the browser. If that is your case, make sure you are using rememberMe: false (or is it default?):
https://github.com/websanova/vue-auth/blob/master/docs/StepByStepGuide.md#using-vue-auth

@jap1968
Copy link
Author

jap1968 commented Nov 30, 2017

I want to log out the user once the token has expired. The users sometimes close the browser, or just close the browser tab of the corporate website, or even they close nothing and suspend the computer. When somebody else wakes the computer up again (maybe next day) I want the previous user being logged out immediately.

I have tested setting rememberMe: false, but nothing changes. I keep having the problem.

@peluprvi
Copy link

peluprvi commented Nov 30, 2017

The users sometimes close the browser, or just close the browser tab of the corporate website

This part sounds like what is the rememberMe: false responsibility. With the browser/tab closed, and after the token expires, when the user reopens the browser and the app, it should not refresh the token. If this is not working, it can be a bug. It can be associated to that #260 (comment)

or even they close nothing and suspend the computer

In that case, you don't want to run the auto refresh each X minutes, but only by routing or after some user action.

To this case, looks like there is a way to disable the auto refresh by setting:
https://github.com/websanova/vue-auth/blob/master/docs/Options.md#refreshdata-url-authrefresh-method-get-enabled-true-interval-30

And then you can manually refresh the token by calling:
https://github.com/websanova/vue-auth/blob/master/docs/Methods.md#refresh

@websanova
Copy link
Owner

I will have to take more thorough look at this over the weekend.

@darrynten
Copy link

Any updates on this"?

@matrunchyk
Copy link

Any update?

@websanova
Copy link
Owner

Just tested this again with vue-resource and the auto logout on refresh fail is working just fine.

If there are issues it's likely with the response being sent back.

The default if you look at vue-resource driver is to check for a 401

https://github.com/websanova/vue-auth/blob/master/drivers/http/vue-resource.1.x.js#L21

You can override this method, but note that you need to override the drivers method not the plugins method.

@oliverschuerch
Copy link

oliverschuerch commented May 22, 2019

Not sure if this is exactly what you're talking about, but axios produces an uncaught error when response status on refresh is 401. Probably this causes further problems.
It happens, because there is no error function defined in the axios.1.x.js driver of vue-auth.

_http: function (data) {
  var http = this.options.Vue.axios(data)
  // data.error is undefined on refresh
  // not happening, when adding: data.error = data.error || function () {}
  http.then(data.success, data.error)

  return http
}

NodeJS: 10.15.3
NPM: 6.4.1

@websanova/vue-auth: 2.21.14-beta
axios: 0.18.0
vue: 2.6.10
vue-axios: 2.1.4
vue-router: 3.0.2

@imzedi
Copy link

imzedi commented Jul 5, 2019

Any update??

@service-paradis
Copy link

The problem is still there. Opening an app where a user was previously logged in, but with an expired token does not work.
An uncaught exception occur and the application will hung.

@Abdallah9Saeed
Copy link

@service-paradis do u have solution for this issue

@imzedi
Copy link

imzedi commented Sep 19, 2019

Hello,
I solved this in my ongoing project.

Problem: If the token gets expired and we call refresh API, an application gets stuck console.log(this.$auth.check()) Giving True means the user is still logged in and there is no auto-logout triggering.

Solution: In my case this is happening because of Axios driver present in this package (node_module/@websanova/vue-auth/drivers/http/axios.1.x.js).

The Axios is not catching the server error response, it just catching a javascript's errors.
please go through this issue axios/axios#960.

So we need to add checkpoint manually inside axios.1.x.js (node_module/@websanova/vue-auth/drivers/http/axios.1.x.js).

    if (res) {
      this.options.Vue.axios.interceptors.response.use(function (response) {
        

        // additional IF checkpoint for catching server error response

          if (response.data.error) {
              response.status = 401;
              res.call(_this, response);
              return Promise.reject(response);
          }

        // Up to this line & keep other code as it is.


          res.call(_this, response);
          return response;

      }, function (error) {

        if (error && error.response) {
          res.call(_this, error.response);
        }
        
        return Promise.reject(error);
      })
    }

So update axios.1.x.js as shown above.

Now if token gets expired or deleted somehow, we are now able to receive server error response (Unauthorized) which will make a user logout.

Testing:
I have set the expiry time to 1 minute (just for testing) then log in to the application and wait for a minute. after that, I just reload the page and I am getting "false" of console.log(this.$auth.check()) which means user get logged out.

Double-check: Again reload the page and checked network tab, there was no more refresh API calling

I hope this will help somebody.
Thank you.

@manuel-84
Copy link

To make it work and redirect to login page when token expired/blacklisted I added the status code 500 into the check for invalidation @ node_module/@websanova/vue-auth/drivers/http/axios.1.x.js

  _invalidToken: function (res) {
    if (res.status === 401 || res.status === 500) {
      return true;
    }
  },

@cwilby
Copy link

cwilby commented Oct 21, 2019

Bumped into this issue today, my problem was with the integration of this library and Laravel jwt-auth.

The refresh endpoint calls auth()->refresh(), which throws a TokenExpiredException when the refresh token has expired. This resulted in an HTTP 500 response, which landed me here.

Solution for me was to catch the exception and call abort(401) in the catch block.

@davidiwezulu
Copy link

davidiwezulu commented Jan 15, 2020

You can actually check if the user is logged-in and manually clear the token session if a 500 error is retrieved. There might be better solutions but this provided a positive result.
handleRedirect(){ this.$http.get('auth/user').then(response => { if ( ! response.data.error) { //---- User is already authenticated ------ } else { //---- Login is required ------- this.$auth.user(''); this.$auth.token(null, ''); this.$auth.watch.data = ''; this.$auth.watch.authenticated = false; this.$auth.watch.loaded = true; this.$router.push({name: 'login'}); } }) }

@websanova
Copy link
Owner

websanova commented Apr 25, 2020

Please note the plugin in fact does not handle 500 cases or any number of many responses that the api may return. This should be handled by the http library and any logic like, logout, or whatever needs to be done can be set there.

Otherwise by default for now it's only handling 401 which will logout the user. With the 500 cases it's not clear it should logout or not, so should be up to app to handle that.

@kosratdev
Copy link

@websanova is there a way to prevent user logout with error code 401 ?

@cwilby
Copy link

cwilby commented Dec 24, 2020

@kosratdev the scenario you're describing sounds like the server should return 403 (forbidden) instead of 401 (unauthorized).

Iirc this library won't log the user out on a 403.

More info here: https://stackoverflow.com/a/6937030

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests