I’m using the code from this page to do authentication using the Okta Sign In Widget:
It works fine in both success and error cases for the most part.
After I get success and onsuccess is called, I need to prevent a redirect until I do a call to my backend API. If that succeeds, I do the redirect. If it fails, I don’t redirect and I want to display a message in the error info box area of the sign in widget.
The problem I’m having is that when the API succeeds, it redraws the widget. This isn’t the case when there’s an error. In that case, the widget displays it above the username input.
I want to have the same behavior as the error case. That is, there is no refresh and the error appears above the username. But once the authState is valid and authState.isAuthenticated is true, the widget disappears on me.
Is there a way to control this so I can grab that element and put my own error text in there?
I found that the root of my problem is that after I put the text into the error area and it displays, I call oktaAuth.signOut(). That, in turn, does a redirect to the logout URI, which is actually the same page as the login page for me. So it looks like it’s refreshing but what’s really happening is a redirect.
I guess that changes my question to this: What is the minimum I can do to end the okta session that will not cause a redirect to what is effectively the same page that I’m already on?
I tried just clearing tokens, revoking various tokens and ending the session but they cause my SPA to hang. To reiterate, do I actually have to call signOut(), or is there a way to avoid that redirect?
as suggested by Andrea in another post, but this hangs my app. The LOGIN button has the continuously running “…” and it never returns control to the sign in widget.
Are you just looking to clear the Okta session at this point?
You may run into issues with third party cookies, depending on how you host your app and your Okta org’s domain, but you could look to add a DELETE /api/v1/sessions/me call to your signout method. That will execute a CORS request to clear the Okta session, without the /logout redirect.
I’m honestly not sure exactly what I want to do. For my use case, the authentication succeeds but then the backend registration for my user fails, so I want to end the session (whatever that means to Okta). On the next login attempt, I need for the sign-in widget to hit the onsuccess() method when the user tries again so that the backend registration happens again. I believe onsuccess for the widget gets called only on a successful authentication.
Is that delete just: oktaAuth.session.close()
And is that delete in addition to the token revoke calls or instead of them?
I tested this and again I get a similar problem with the Sign In Widget. I see the 204 response from the close() request but then the Widget’s LOGIN button shows the “…” and never returns control. If I reload the page, the widget rerenders correctly.
If you are trying to close both the application session AND the IdP (Okta) session, then yes, you will still want to revoke the tokens and remove them from storage.
Do you have any idea why I never get control back to the Widget? I prevented the reload of the whole page and I just recreate the widget to force it to reset, but this isn’t ideal. Once the session is closed, I’d expect the widget to be active again.
And unfortunately, after trying this, oktaAuth.revokeIdToken() hangs. It never returns.
I still have the outstanding problem of the Okta Sign In Widget hanging after I close the session so I have to refresh the widget. It’s not ideal visually because I have to wait a few seconds then remove and rebuild the widget. Do you have any idea why the widget doesn’t return control to the user? I’m seeing successful returns from the network so I don’t know why the widget doesn’t know that.
After I looked at the widget with the element inspector, I see that it has the disabled class type set. That appears to be what’s making it appear hung. Is there a way to turn off the disabled attribute? It appears to be on the sign in button itself rather than the entire widget component.
It’s a little hard to tell from this, I think, but what you’re seeing in the network trace is a 401 failure to the call to my backend. That happens after a successful authentication with Okta. So as far as the auth server is concerned, I’m successfully logged in. After the authentication with Okta, I do that call to login which fails from my backend (as I’m expecting). After the login fails, you can see the calls to delete the session with Okta (which you gave me yesterday) and appear to be working.
Once that login fails, I close the session out with Okta and never do a redirect. At that point, the ‘…’ continues to appear in the Sign In button as shown in the image. In the image, the “User account is not active” is a message from my backend, not Okta. Also, the blue image is entirely an Okta Sign In Widget and it’s just restyled for my needs. The other controls remain active. It’s just the Sign In button that remains disabled. I think maybe the widget is depending upon a redirect to reenable it. The only way I’ve found to do that is to remove then recreate the widget. I really want to just get control back.
This is how I do the signout:
const oktaSignOut = async () => {
if (oktaAuth && authState && authState.isAuthenticated) {
await oktaAuth.session.close();
// the hook should have been looking up the token but it wasn't so this does
oktaAuth.tokenManager.get('idToken').then(async (token) => {
await oktaAuth.revokeIdToken(token);
});
oktaAuth.tokenManager.get('accessToken').then(async (token) => {
await oktaAuth.revokeAccessToken(token);
});
await oktaAuth.revokeRefreshToken();
await oktaAuth.tokenManager.clear();
}
What method are you using right now to render the widget? Are you using showSignIn?
And yeah, my first thought would have been to hide/show or remove the widget after the flow completes. Is there a downside to doing it this way, or are you just trying to explore other options?
I’m using this:
widget
.showSignInToGetTokens({
el: widgetRef.current,
})
.then(onSuccess)
.catch(onError);
The downside is that when I remove the widget, the whole thing disappears from the screen then is replaced and it no longer has the error message that I’m trying to display. So I have to wait some arbitrary amount of time then remove the widget. It’s a poor user experience.
I’d really rather just have a way to reset the widget without having to remove it from the screen only to replace it immediately. Disappearing/reappearing controls is a lousy user experience so I’d rather avoid it if I can.
Unfortunately I don’t know a way around this, its just not a use case that the widget was designed to handle (fully logging a user in, logging them back out, and prompting for login again).