Skip to content

PKCE refresh token expired after sleep mode #864

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

Open
CedricHg opened this issue Jun 22, 2020 · 6 comments
Open

PKCE refresh token expired after sleep mode #864

CedricHg opened this issue Jun 22, 2020 · 6 comments
Labels
feature-request Improvements and additions to the library.

Comments

@CedricHg
Copy link

CedricHg commented Jun 22, 2020

Describe the bug
I'm using the PKCE flow against a Keycloak (Redhat SSO) server and I get a refresh_token which works fine as long as the PC remains active.
The Keycloak refresh token expiration time is set to 30 minutes.

An (edge) case we found is a user locks and leaves their PC to go do something else and comes back when this refresh token has expired. Upon coming out of sleep mode it appears that the refreshInternal function then triggers and attempts to post to the token endpoint with this now expired refresh token. The response is a 400 as you can imagine.

Am I missing a check that I need to do myself or a certain feature? I suppose I can rig angular-oauth2-oidc up to do a new login rather than a refresh if it hasn't done one within a certain time but then how do I "block" the standard automatic refresh?

Expected behavior
Support refresh token expiration

Desktop (please complete the following information):

  • OS: Windows 10
  • Browser Chrome
  • Version 83.0.4103.106
@jeroenheijmans
Copy link
Collaborator

It makes sense that the library is robust against this situation, and (if needs be optionally, behind a flag) updates internal state to reflect the fact that a user got logged out after all.

There's no such feature at the moment I think. So for the moment you will need to cover it in your own application (for example with a custom HttpInterceptor).

@jeroenheijmans jeroenheijmans added the feature-request Improvements and additions to the library. label Jun 22, 2020
@Istanful
Copy link

@jeroenheijmans I am fairly sure we are experiencing the same issue in our app. Do you have any suggestions on how to fix it with a custom HttpInterceptor?

The best way I can come up with is to mod the current interceptor to check the validity of the current token. Currently it picks the first truthy token, which can be expired.

So instead of:

return merge(
of(this.oAuthService.getAccessToken()).pipe(
filter(token => (token ? true : false))
),
this.oAuthService.events.pipe(
filter(e => e.type === 'token_received'),
timeout(this.oAuthService.waitForTokenInMsec || 0),
catchError(_ => of(null)), // timeout is not an error
map(_ => this.oAuthService.getAccessToken())
)
).pipe(
take(1),
mergeMap(token => {
if (token) {
const header = 'Bearer ' + token;
const headers = req.headers.set('Authorization', header);
req = req.clone({ headers });
}
return next
.handle(req)
.pipe(catchError(err => this.errorHandler.handleError(err)));
})
);

I would do something along the lines of:

    return merge(
      of(this.oAuthService.getAccessToken()).pipe(
        filter(token => (token ? true : false))
      ),
      this.oAuthService.events.pipe(
        filter(e => e.type === 'token_received'),
        timeout(this.oAuthService.waitForTokenInMsec || 0),
        catchError(_ => of(null)), // timeout is not an error
        map(_ => this.oAuthService.getAccessToken())
      )
    ).pipe(
      take(1),
      mergeMap(token => {
        if (this.oAuthService.hasValidAccessToken()) {
          const header = 'Bearer ' + token;
          const headers = req.headers.set('Authorization', header);
          req = req.clone({ headers });
        } else {
          return this.oAuthService.logOut();
        }


        return next
          .handle(req)
          .pipe(catchError(err => this.errorHandler.handleError(err)));
      })
    );

I understand this would drastically change the behaviour of the interceptor, but I'm looking for a safe way to guarantee that invalid requests are not sent.

@jeroenheijmans
Copy link
Collaborator

(Just a quick reply, perhaps not a completely thought through answer =>) Interceptors are in a chain I think, and I believe in our production app we just have an extra one in place to handle 4xx http responses and act accordingly. So add your own, new interceptor to the chain, make it sniff out OIDC calls that return a specific status, and act accordingly?

@Istanful
Copy link

@jeroenheijmans That is correct. If I provide a custom interceptor after your module I can e.g. find out if we are in an invalid state and act accordingly. I'll do so in the meantime, but I'm curious if the library could handle this out of the box and if so how?

@amihaiemil
Copy link

amihaiemil commented Nov 28, 2022

@jeroenheijmans Do you have maybe some feedback here? My colleagues are complaining about this same exact bug, but I could not reproduce it at all!

Maybe it has been fixed in the meantime and you guys forgot to close this Issue (it's quite old)?

@jeroenheijmans
Copy link
Collaborator

Heya @amihaiemil! Sorry to hear you're having issues. However, see #1280, I've stepped back from moderating, so we'll have to rely on yourself or the community to step up and further investigate this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Improvements and additions to the library.
Projects
None yet
Development

No branches or pull requests

4 participants