okta / okta-oidc-js

okta-oidc-js
https://github.com/okta/okta-oidc-js
Other
394 stars 232 forks source link

Refresh Token #750

Open seanmalek opened 4 years ago

seanmalek commented 4 years ago

I'm submitting this issue for the package(s):

I'm submitting a:

Current behavior

We have web client app that redirects the user to login page at start, however when they log in there is no refresh-token, idtoken expires in 1 hour and no matter what after the hour the user needs to login again, we like to get refresh token without user interaction, we are using @okta/okta-react version 1.4.1 Not sure what is the best approach, I did see any instance of tokenManger that I can use

Expected behavior

when I set the tokenManger and Autorenew to true in <Security props then I am assuming that the renew would happen automatically, what am i missing?

Minimal reproduction of the problem with instructions

Extra information about the use case/user story you are trying to implement

Environment

swiftone commented 4 years ago

Hi @seanmalek - Thanks for the report.

If I'm understanding your report correctly, your desire matches the expectation: In situation without a refresh token, such as with a SPA, the okta-react client should automatically make a call to the issuer domain and attempt to get a new token. If that call fails (for example, they logged out of the issuer domain, or their session there expired) they will have to login again.

We have a report that this autoRenew isn't working for everyone ( https://github.com/okta/okta-oidc-js/issues/744 ) and are currently investigating. I'll be able to comment soon on whether I can recreate the problem.

swiftone commented 4 years ago

Following up on this issue:

If my okta dashboard settings (note: Not specific to one application) have a policy that expires my "session" (by which it means the session on the okta issuer domain) faster than the idtoken expires (1 hour), then when authentication is required the user will be directed to login. This is working as intended and the decision of HOW to login can be overridden by passing the onSessionExpired() callback to <Security> as noted in the README (https://github.com/okta/okta-oidc-js/tree/master/packages/okta-react#configuration-options)

If my okta dashboard settings have NOT altered the default session expirations, until that session expiration is reached an expired token will cause the library to call out to the issuer domain and get new tokens. This will only happen when the token is needed, not immediately when the token expires.

I've not been able to replicate a different situation. Can you offer any details (or share with our support team) where these do not describe your situation?

gvdhorst commented 4 years ago

I do not use okta-react but I think I am experiencing the same issue with a combination of oidc-middleware and jwt-verifier.

When the access token has expired (by default after 1 hour, but can be reduced to 5 minutes to make testing this easier) I would expect req.isAuthenticated() to return false and oidc.ensureAuthenticated() to fetch a new access token (using a refresh token) before proceeding. Instead, req.isAuthenticated() returns true and oidc.ensureAuthenticated() seems to just call next() leaving the expired access token in place. jwtVerifier.verifyAccessToken() will now throw an error because the access token has expired.

gabrielmicko commented 4 years ago

This is causing us issues as well.

swiftone commented 4 years ago

per #744 Internal ref: OKTA-291520 Also, documentation/concept issues per #721

christopherhuii commented 4 years ago

Experiencing this issue as well.

vahedq commented 4 years ago

Same issue here!

swiftone commented 4 years ago

Updating this - we've noticed the attention and are working on crafting a solution that will make the meaning of our terms clear (and what they don't mean) and giving a better experience. Getting that right is taking some time.

In the meantime, we recommend NOT considering isAuthenticated to mean "user has valid tokens" (the current meaning is more "the user has retrieved at least one token successfully at some point).

You likely want to ask more specific questions (such as getUser/getUserInfo). Hopefully that can help while we improve the situation.

DavidLozzi commented 4 years ago

Do we have to do anything specific to enable the refresh token to work? I can't find documentation on how to enable it with the okta react library.

swiftone commented 4 years ago

@DavidLozzi -

1) In case it matters, it is not technically a refresh token. Refresh tokens are only used server-side, not client side, so it isn't used with react.

2) autoRenew defaults to true (currently - this may change in an upcoming major version), so no explicit step needs to be taken. This is a parameter passed to the okta-auth-js tokenManager (in the okta-react README here: https://github.com/okta/okta-oidc-js/tree/master/packages/okta-react#configuration-options we link to https://github.com/okta/okta-auth-js#configuration-reference where the option is listed)

3) As mentioned above, we are actively working on tracking down an issue where autoRenew doesn't seem to be autorenewing for some users (https://github.com/okta/okta-oidc-js/issues/744). Note that autoRenew will only last for as long as the issuer domain session cookie remains valid - it is not a refreshToken.

DavidLozzi commented 4 years ago

Thanks, we're having better success with the 3.0.2 library so far. We also have lines open with Okta support. Thanks!

sarath-sasikumar commented 4 years ago

Hi @DavidLozzi Were you able to solve this issue? At the moment, I also face the issue of being redirected to login when the hour mark is hit, forcing users to lose continuity

Thanks, we're having better success with the 3.0.2 library so far. We also have lines open with Okta support. Thanks!

swiftone commented 4 years ago

@sarath-sasikumar: We have some updates to okta-react in the works, but in the meantime make sure you're trying with okta-react 3.0.3+ and that it installed with okta-auth-js 3.2.2

You can see some of our other upcoming changes here: https://github.com/okta/okta-oidc-js/pull/848

As those changes involve backward-incompatible changes to our API, they will be released in a major version bump, but you can try them out locally to see if they help in advance if you wish.

sarath-sasikumar commented 4 years ago

@swiftone Is it possible for the tokens to be silently refreshed even if the session has expired. Across multiple applications, the policy to expire sessions is less than the one hour set for ID tokens hence the refresh operation is failing. Is there any workaround for this problem, since this is causing huge issues for users, who are forced to log in again and again, causing disruption in their work, and I don't want to change the session expiration policy for all the other applications.

DavidLozzi commented 4 years ago

@sarath-sasikumar Kind of? Here's where we're at:

As long as the user is active on the site, they can go all day, it'll keep renewing and staying active.

If the user is not active, after that 2-hour mark, even though the access token is set to 24hours, they still expire and have to reauth. We have a support ticket open and working with support. I'll be sure to post back once we have some progress.

sarath-sasikumar commented 4 years ago

@sarath-sasikumar Kind of? Here's where we're at:

  • We are using @okta/okta-react v3.0.2.
  • Our access token expirations are set to 24 hours, but session expiration is 2 hours
  • We are using authService.getAccessToken() to get the access token, through Okta's libraries. This method, to my understanding, handles getting a new access token if/when needed.
  • We also added a little script that runs against https://logon.okta.com/api/v1/sessions/me to see if the user's session is active, and then it refreshes the session calling https://logon.okta.com/api/v1/sessions/me/lifecycle/refresh.

As long as the user is active on the site, they can go all day, it'll keep renewing and staying active.

If the user is not active, after that 2-hour mark, even though the access token is set to 24hours, they still expire and have to reauth. We have a support ticket open and working with support. I'll be sure to post back once we have some progress.

Thanks for this @DavidLozzi I think this alligns with my use case as well. Will it be possible for you, to give some insight into the script that you have used for https://logon.okta.com/api/v1/sessions/me

DavidLozzi commented 4 years ago

@swiftone it appears that <SecureRoutes is causing this issue? We've removed using Okta SDKs to get the user info, instead just reading localStorage directly. Can you point me to the code that might be causing this? I can try it out in my own fork

swiftone commented 4 years ago

@DavidLozzi - We've touched a few issues that may impact your case, try out okta-react 3.0.4 and make sure it's running okta-auth-js 3.2.2+

You may also be running into a problem like the one described here: https://github.com/okta/okta-oidc-js/issues/842. A workaround is in that issue, depending on what you need.

But here's some background:

okta-auth-js (the core library managing the tokens) currently works by replacing expired tokens when they are accessed. If a user is idle and both a token and their session expires, when the user acts again (and requests a token from okta-auth-js), okta-auth-js will notice the token needs to be replaced and will try to get one from the issuer in the background. If the session is expired, this will fail.

Recently, okta-react 2.x and 3.x shifted towards keeping a copy of the tokens and not always requesting them asynchronously from okta-auth-js. Unfortunately, I missed a few spots and okta-react kept some expired tokens and didn't replace them. We believe okta-react 3.0.4 fixes all the last of the related bugs.

cfbao commented 4 years ago
  • We also added a little script that runs against https://logon.okta.com/api/v1/sessions/me to see if the user's session is active, and then it refreshes the session calling https://logon.okta.com/api/v1/sessions/me/lifecycle/refresh.

@DavidLozzi I considered doing something like this in our web app, but wasn't sure if it's considered proper security practice, so opted for a different (but more complicated) approach that worked for us.

I wonder what Okta's official advice on this is. Is that session refresh route supposed to be used in such a way? If so, would it make sense for this SDK include built-in support for it? @swiftone

shuowu commented 4 years ago

@cfbao @DavidLozzi As you figured out, the SDKs token refresh is based on valid OKTA SSO session. You can customize the session expiration in your OKTA developer console by following: Applications -> Your SPA application -> Sign On -> Sign On Policy -> Click Add rule button -> Checking the Prompt for re-authentication in Actions section.

DavidLozzi commented 4 years ago

@swiftone is there code in here that removes the idToken from local storage when it expires? That is causing our headaches... Our accessToken is 24hrs, but idToken is 1hr. We are pulling the user's email address from the idToken. So when it's not there, my code assumes the token is bad and asks the user to log back in.

My workaround is to copy the data out of the idToken so when it does expire, it doesn't affect us, trying this out now.

shuowu commented 4 years ago

@DavidLozzi Tokens will be removed from storage as long as they are expired. You can also use the getuser API to get the latest user info.

sarath-sasikumar commented 4 years ago
  • We also added a little script that runs against https://logon.okta.com/api/v1/sessions/me to see if the user's session is active, and then it refreshes the session calling https://logon.okta.com/api/v1/sessions/me/lifecycle/refresh.

@DavidLozzi I considered doing something like this in our web app, but wasn't sure if it's considered proper security practice, so opted for a different (but more complicated) approach that worked for us.

I wonder what Okta's official advice on this is. Is that session refresh route supposed to be used in such a way? If so, would it make sense for this SDK include built-in support for it? @swiftone

@cfbao I had to take this approach as well, because I did not want to change the session expiration just for one application. However, is there any better approach to keeping the okta session alive other than periodic refresh before expiration. It would be good if you can give some insight into the alternative approach you mentioned if it aligns with my requirement. Also any Inputs from @shuowu @swiftone

shuowu commented 4 years ago

@cfbao @DavidLozzi As you figured out, the SDKs token refresh is based on valid OKTA SSO session. You can customize the session expiration in your OKTA developer console by following: Applications -> Your SPA application -> Sign On -> Sign On Policy -> Click Add rule button -> Checking the Prompt for re-authentication in Actions section.

@sarath-sasikumar have you tried the setting mentioned above? I think it should be able just to customize session expiration time for one specific app.

DavidLozzi commented 4 years ago

We tried that setting @shuowu and it didn't do anything, idToken expiration was still 1 hour. From talks with Okta support, they said to extend the expiration of the idToken we'd have to create a hook to define it. We don't want to go down that route for numerous reasons.

Our current approach seems sound.

boom, done ;)

DavidLozzi commented 4 years ago

I'm curious though, where in the library does it delete the idToken? I was trying to find it but couldn't. Can someone point me to it?

shuowu commented 4 years ago

@DavidLozzi Want to double-check first if you are on the latest react-sdk version (3.0.4), there are several fixes there to guarantee the autoRenew work properly. Also, the setting only can extend the OKTA SSO session expiration time, but not the idToken.

If you are with the latest react 3.x, then looks like you are in the situation that you have a long-live accessToken (24hrs), but a short idToken (1hr), in this case, the default SecureRoute behavior will still keep you login even one of the token gets expired. However, you are not able to get the expired idToken renewed since your okta session is also expired. Some suggestions:

I'm curious though, where in the library does it delete the idToken? I was trying to find it but couldn't. Can someone point me to it?

A quick pointer can be https://github.com/okta/okta-auth-js/blob/master/packages/okta-auth-js/lib/TokenManager.js#L184 Renew failure will cause tokens to be removed from the storage. We are also working on refactoring the autoRenew process, it will be released in the next major version release.

cfbao commented 4 years ago

It would be good if you can give some insight into the alternative approach you mentioned if it aligns with my requirement.

@sarath-sasikumar There's some setup in our company that automatically logs us into Okta when we're on company network & known devices/browsers & some other conditions. I don't know the details as I didn't set this up. I do still need to solve a race condition when logins happen. But overall this is good enough for the internal tool we're maintaining. YMMV.