fenichelar/ember-simple-auth-token

Page does hard refresh when session invalidated

Redsandro opened this issue · 27 comments

When token-refresh fails, or is too late, or the session invalidates (automatically or manually), the page does a hard refresh. How do I stop this?

I still want to "change" my app, so an event would be nice, but I do not want a hard refresh. This is a SPA.

I'm using authenticator:jwt and mistakenly posted an issue here: myartsev/ember-simple-auth-jwt#52

@Redsandro This library never does anything to cause a page refresh. Can you post the code needed to reproduce this behavior so I can take a look?

Triggering sessionDataInvalidated causes a hard refresh for me. Here are my environment.js settings:

	ENV['ember-simple-auth-token'] = {
		serverTokenEndpoint: `${ENV.APP.API}/token`,
		serverTokenRefreshEndpoint: `${ENV.APP.API}/refresh`,
		tokenExpirationInvalidateSession: true,
		refreshAccessTokens: true,
		refreshLeeway: 10, // 300,
	}

When token-refresh fails (handleTokenRefreshFail):

https://github.com/jpadilla/ember-simple-auth-token/blob/65435bd7ddc579382276fb276132a722b8813499/addon/authenticators/jwt.js#L316-L319

And when the session expires (handleAccessTokenExpiration in the case of tokenExpirationInvalidateSession: true):

https://github.com/jpadilla/ember-simple-auth-token/blob/65435bd7ddc579382276fb276132a722b8813499/addon/authenticators/jwt.js#L347-L349

This causes invalidationSucceeded to be triggered upstream.

https://github.com/simplabs/ember-simple-auth/blob/0ab8847ed94812c391f66f79c645127abd771f95/addon/internal-session.js#L141

But I am not extending it. I don't know why the refresh happens.

@Redsandro Are you able to provide a complete example of this behavior? I can't reproduce the behavior with the information provided and I don't see anything that would cause this behavior. In all of my applications using this library, there is not a hard refresh when invalidationSucceeded is triggered.

@fenichelar it's not easy because some code is not mine/libre, and I would need to spoof the backend and everything.

I will explore opinions from upstream first. If I can't get a hint as to what might cause this, I will go the extra miles. Although there has to be a way to listen for an event and track what triggered it.

@fenichelar said:

In all of my applications using this library, there is not a hard refresh when invalidationSucceeded is triggered.

That's interesting, because I got word from upstream that:

Reloading is ESA's default behavior

How do your apps prevent it from happening?

Wait, just to be clear... are you using both TokenAuthorizerMixin and ApplicationRouteMixin?

Application adapter:

import TokenAuthorizerMixin from 'ember-simple-auth-token/mixins/token-authorizer'

Application router:

import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin'

On closer examination, I don't believe invalidationSucceeded is actually being called in any of my applications.

I am using TokenAuthorizerMixin but I am not using ApplicationRouteMixin.

I take it back, I think invalidationSucceeded is called it just doesn't do anything.

invalidationSucceeded is called it just doesn't do anything.

Ah, okay, I get it. That's because you don't use the ApplicationRouteMixin.

I think I might be using this wrong. I assumed I needed ApplicationRouteMixin for handling the session and the automated refresh_token business.

I only need TokenAuthorizerMixin? It will handle the session refreshing? I can remove ember-simple-auth? It's not a dependency/requirement?

Indeed, ApplicationRouteMixin is optional. Do I even need to install ember-simple-auth next to ember-simple-auth-token, or can I remove it entirely?

(Btw, setting refreshAccessTokens to false does nothing, it will still refresh tokens.)

ember-simple-auth is a required dependency of ember-simple-auth-token. You don't need to manually install it or add it to your package.json.

I just did a quick test with refreshAccessTokens set to false and it did not attempt to refresh the token. Can you show me your config?

	ENV['ember-simple-auth-token'] = {
		serverTokenEndpoint: `${ENV.APP.API}/token`,
		serverTokenRefreshEndpoint: `${ENV.APP.API}/refresh`,
		tokenExpirationInvalidateSession: true,
		refreshAccessTokens: false,
		refreshLeeway: 10, // 300,
	}

JWT session expiration time is 15 seconds, and refreshLeeway 10, so that I only need to wait 5 seconds to test this out.

I can't seem to reproduce this, can you provide a working sample?

Closing. Let me know if you still have this issue.

It's doing this to me too. Somewhere in the code it's triggering a hard refresh and losing the token state.

This only happens locally for me.

I've tried just copying the local storage from my production app (as it's pointing to the same database) but that gets replaced immediately. No errors anywhere in the logs.

@allthesignals

  1. What version of ember-simple-auth-token are you using?
  2. What version of ember-simple-auth are you using?
  3. What version of ember are you using?
  4. Are you using either of the mixins?
  5. What is in your ember-simple-auth-token config?
  6. Can you provide a sample app that can reproduce the hard refresh?

@fenichelar thank you so much for replying I really appreciate it.

  1. "ember-simple-auth": "^1.8.0",
  2. "ember-simple-auth-token": "^4.0.6",
  3. ember: 3.15
    
  4. Using many many mixins but still using the classic object model including TokenAuthorizerMixin
    'ember-simple-auth-token': {
      serverTokenEndpoint: `${getHost(environment)}/auth/v1/login`,
      refreshAccessTokens: false,
      tokenExpireName: 'exp',
      tokenExpirationInvalidateSession: true,
    },
  1. This thing is a behemoth so not really but the repo is available here https://github.com/NYCPlanning/ceqr-app

What is mysterious to me is this behavior doesn't occur in production: https://www.ceqr.app.

Further context, I've inherited this app and am unsure how to proceed. I just cannot get it to authenticate. Attempts to cUrl the login endpoint in the backend work fine — they return the token. I can even observe a 200 OK response in the frontend. But I get a "transition aborted" — unless it's a red herring, it seems to be interrupting and I don't know why.

@allthesignals Thank you. I'm not completely following what the issue is. Can you walk through what is happening in a little more detail?

@allthesignals Thank you. I'm not completely following what the issue is. Can you walk through what is happening in a little more detail?

Yes, here's what I'm observing:
https://user-images.githubusercontent.com/5004319/116729040-ae651680-a9b4-11eb-9e8c-fc07927cf69e.mov

This is local development. When I successfully login (I am confirm through backend logs), it seems to try to transition to a new route, but does a hard refresh instead. This hard refresh causes the token to never be persisted in memory in the application instance.

This doesn't seem to occur in the production deployment of the site.

Even a vague guess at what is causing this would help...

Thank you!

Can you expend the transition aborted console log and provide the full output?

Can you expend the transition aborted console log and provide the full output?

Yes — I don't think it's very helpful though. I think something more serious is being buried... let me see if I have an error hook in a route somewhere:

"TransitionAborted: TransitionAborted
at logAbort (http://localhost:4200/assets/vendor.js:77099:12)
at PrivateRouter.transitionDidError (http://localhost:4200/assets/vendor.js:41243:44)
at http://localhost:4200/assets/vendor.js:76855:51
at invokeCallback (http://localhost:4200/assets/vendor.js:79339:17)
at publish (http://localhost:4200/assets/vendor.js:79322:9)
at publishRejection (http://localhost:4200/assets/vendor.js:79258:5)
at http://localhost:4200/assets/vendor.js:73757:53
at invokeWithOnError (http://localhost:4200/assets/vendor.js:72053:18)
at Queue.flush (http://localhost:4200/assets/vendor.js:71935:13)
at DeferredActionQueues.flush (http://localhost:4200/assets/vendor.js:72132:21)"

Screen Shot 2021-04-30 at 1 34 24 PM

Ah, here's some more information (There indeed was an error hook swallowing up valuable information):

Okay, so the transitionAbort error might be happening because of an immediate 401:

Error: Ember Data Request GET http://localhost:3000/api/v1/projects returned a 401
Payload (application/json; charset=utf-8)
[object Object]
at ErrorClass.AdapterError (http://localhost:4200/assets/vendor.js:117431:29)
at new ErrorClass (http://localhost:4200/assets/vendor.js:117464:24)
at Class.handleResponse [as _super] (http://localhost:4200/assets/vendor.js:119364:18)
at Class.handleResponse (http://localhost:4200/assets/vendor.js:166925:19)
at Class.superWrapper [as handleResponse] (http://localhost:4200/assets/vendor.js:49590:22)
at ajaxError (http://localhost:4200/assets/vendor.js:119699:25)
at ajaxErrorHandler (http://localhost:4200/assets/vendor.js:119778:12)
at Class._hash.error (http://localhost:4200/assets/vendor.js:119467:25)
at fire (http://localhost:4200/assets/vendor.js:9519:31)
at Object.fireWith [as rejectWith] (http://localhost:4200/assets/vendor.js:9649:7)

So that invalidates something probably and causes a refresh or navigation to login? Looking at the XHR history is interesting:
image

What's odd about the "successful" login request is that it fails to load the response data?
image

I'm not sure if this is even how browsers behave, but perhaps there's some race condition.

EDIT:

Plot thickens... this.session.authenticate throws the following:

TypeError: Cannot read property 'email' of undefined
at Class.sessionAuthenticated (labs-ceqr.js:20510)
at Class.superWrapper [as sessionAuthenticated] (vendor.js:49590)
at Class. (vendor.js:166708)
at sendEvent (vendor.js:31263)
at Class.trigger [as _super] (vendor.js:46377)
at Class.trigger (vendor.js:167293)
at Class.superWrapper [as trigger] (vendor.js:49590)
at Proxy. (vendor.js:167264)
at sendEvent (vendor.js:31263)
at Proxy.trigger (vendor.js:46377)

Can you expend the transition aborted console log and provide the full output?

You can disregard this now... I think this had to do with some weird dep resolutions issues for fetch (competing with jQuery maybe?) The particulars of the faulty fetch shim I was using were probably interfering with how ESA-token makes requests.

@allthesignals Is everything working now or just the transition?

@allthesignals Is everything working now or just the transition?

Everything is working now but my advice (or shot in the dark) for others would be to make sure there are no weird issues with ember-fetch. The fix described in that issue thread seemed to cause the issue. I got around it by switching to an earlier version of node.