Open joao-fonseca-inmarsat opened 4 years ago
@joao-fonseca-inmarsat okta-auth-js, the upstream SDK of okta-vue
, has already implemented hidden iframe logic to renew tokens in the background. The getAccessToken from okta-vue
only returns the token from storage. I think the error you saw was thrown from auth-js
, which means get a new token failed because of current session has expired.
Can you try the tokenManager.renew
and isAuthenticated
options from https://github.com/okta/okta-vue#auth to see if it still introduce errors?
Also, there is a thread tracks the discussion of the error you saw in app, please check https://github.com/okta/okta-oidc-js/issues/460
Ah, I just got linked here from https://github.com/okta/okta-oidc-js/issues/460. I am currently using okta-auth-js solo, this may be the error I'm running into. Seeing this in Safari though.
I am able to see 1-2 successful renewals while sitting on the page -- this usually only happens when I go back to the page after having closed the tab for a couple hours.
I think the error you saw was thrown from
auth-js
, which means get a new token failed because of current session has expired.
The session is not expired. If I access the Okta dev-*.okta.com of my account on a separate tab, I can see the session is still there. When I list the cookies, I can see that JSESSIONID doesn't have "samesite=none", which Chrome requires when accessed from an iframe.
On my page, when the library tries to renew, I see that the cookies for dev-*.okta.com are empty - Chrome is just not allowing the session cookies to be loaded from the iframe.
Everything works from Firefox, because it doesn't enforce the "samesite=none" policy.
The fix is very simple - the dev-*.okta.com servers must set the "samesite=none" attribute of the JSESSIONID cookie.
@joao-fonseca-inmarsat You can customize browser cookies setting with https://github.com/okta/okta-auth-js#cookies
@joao-fonseca-inmarsat You can customize browser cookies setting with https://github.com/okta/okta-auth-js#cookies
I tried that and it didn't work. I think those settings define how the library stores its own cookies (if any) in the web page.
The cookies that are the source of this problem are the JSESSIONID and other cookies that the Okta SSO server at "dev-*.okta.com" returns when the user logs in. It's that server that needs to set "samesite=none" on the cookies. I didn't find any option to configure this on the dashboard.
@joao-fonseca-inmarsat I am not aware of any auto renewal issue in chrome (with default cookies setting). Can you check your browser settings to see if it's blocking third party cookies or not?
@joao-fonseca-inmarsat I am not aware of any auto renewal issue in chrome (with default cookies setting). Can you check your browser settings to see if it's blocking third party cookies or not?
I'm using the default cookie settings from Chrome.
Note that this bug manifests itself from within an iframe; it's very simple to reproduce:
-Create a web page that requires a login from the user -Configure okta-auth with expireEarlySeconds to a large value, so that you don't need to wait hours for a refresh -In the main web page, add an iframe containing a second page -The second page runs a script that periodically calls getAccessToken() every 30 seconds (you can log it to the console) -When okta-auth decides to refresh the token, you will get the error message
@joao-fonseca-inmarsat Then it's back to my first comment (https://github.com/okta/okta-auth-js/issues/461#issuecomment-685828554). Wondering why you want to wrap the getAcceesToken in an iframe. In auth-js 3.x, getAccessToken
triggers a renew process (happen in iframe). In auth-js 4.x, getAccessToken
is only getting token from the storage. By either way, I don't think you need to wrap the process in an iframe in your app.
If you are using okta-vue
, I think you most probably are still using auth-js@3.x
@joao-fonseca-inmarsat By either way, I don't think you need to wrap the process in an iframe in your app.
If you are using
okta-vue
, I think you most probably are still using auth-js@3.x
Yes, I'm using okta-vue 2.1.0/okta-auth-js 3.2.3.
I removed the iframe, and got the same result. Here's an abridged version of my code:
const routes = [
{
path: '(redirect uri)',
component: Auth.handleCallback()
},
{
path: '/',
component: () => import('pages/Page.vue'),
meta: {
requiresAuth: true
}
},
// Always leave this as last one,
// but you can also remove it
{
path: '*',
component: () => import('pages/Error404.vue')
}
]
Vue.use(VueRouter)
const oktaConfig = {
issuer: '(my issuer)',
clientId: '(my client id)',
redirectUri: '(redirect URI)',
scope: [scopes]
pkce: true,
tokenManager: {
autoRenew: true,
expireEarlySeconds: 3420
}
}
Vue.use(Auth, { ...oktaConfig })
<!-- The page -->
<template>
<p>Hello</p>
</template>
<script>
export default {
data () {
return {}
},
created () {
var me = this
setInterval(function () {
if (me.$auth) {
me.$auth.getAccessToken().then(function (accessToken) {
console.debug('Fetched access token', accessToken)
})
}
}, 10000)
}
With the above code, I sometimes get an "Invalid redirect URI" response. I think during the initial login, the redirect gets back with some URI parameters (e.g. "implicit/callback?code=xxxx"), which somehow is stored by okta-auth. If I don't do anything, the auto renewal sends the redirect uri as "implicit/callback?code=xxxx" and the server complains about it.
To work around the above, after login I reload the page (clicking enter in the address bar); this resets the information kept by okta-auth, and the auto renewal sends the correct redirect URI.
But, then I get the "The client specified not to prompt, but the user is not logged in." problem.
@joao-fonseca-inmarsat
The error, The client specified not to prompt, but the user is not logged in
, only mean your app's session is expired when attempt to renew tokens, and the users need to re-login to get a new valid session.
Per the code, looks like the timer you add only triggers the get token process (renew process included), but didn't handle the failure case (the error you see). I would suggest you check the sample code, which is doing the passive auto renew process without an active timer in the app. https://github.com/okta/samples-js-vue/blob/master/okta-hosted-login/src/App.vue#L84
@joao-fonseca-inmarsat The error,
The client specified not to prompt, but the user is not logged in
, only mean your app's session is expired when attempt to renew tokens, and the users need to re-login to get a new valid session.Per the code, looks like the timer you add only triggers the get token process (renew process included), but didn't handle the failure case (the error you see). I would suggest you check the sample code, which is doing the passive auto renew process without an active timer in the app. https://github.com/okta/samples-js-vue/blob/master/okta-hosted-login/src/App.vue#L84
As I said in a previous post, the app's session is not expired. I can confirm that by accessing the dev-*.okta.com web pages on a different tab. Also, I had only logged in 3 minutes before (I'm using expireEarlySeconds=3420 to speed up the renewal process).
Again: the session expired error is caused by Chrome and the iframe used by okta-auth; Chrome requires cross-domain cookies (in this case dev-*.okta.com) to be set with "samesite=none" and they are not. When okta-auth tries to read the JSESSIONID cookie, it doesn't see it and thinks there's no session. But there is (and I've said it many times now), it's Chrome who is preventing the cookie from being read.
The example app you mention is not what I want. Before rendering each page, it verifies if the user is authenticated; if it's not, it will redirect to the Okta server. The user will perceive this as a blank screen for a few moments. Also, I'm on a SPA - the user may work for extended periods of time on the same page, which will be doing a lot of back-end requests. I don't want the web page to suddenly become blank while there's a token renewal in progress.
I'm using okta-vue to build a SPA, and using an invisible iframe embedded in the page to try renewing the token without any redirects visible to the user. Basically, the iframe periodically calls getAccessToken() to ensure the auto renewal kicks-in, even if the user is not at his desk.
This works in Firefox, but in Chrome get "error.errorCode: login_required, error.description: The client specified not to prompt, but the user is not logged in." and "Session has expired or was closed outside the application.".
Upon investigation, I think this is what's happening:
The Okta web server needs to set the samesite=none, secure=true on the session cookies. I can see secure=true, but samesite is empty.
Is there a way to enable this on the server? Any work-arounds?