Skip to content
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

When calling signOut() revokeAccessToken() seems not be called. #393

Closed
Taras-R opened this issue Jun 9, 2020 · 24 comments
Closed

When calling signOut() revokeAccessToken() seems not be called. #393

Taras-R opened this issue Jun 9, 2020 · 24 comments

Comments

@Taras-R
Copy link

Taras-R commented Jun 9, 2020

Hi Okta team, we have faced with an issue and would like to describe it here. Maybe we do not understand something clear enough, so hope you can clarify a bit.

We are using latest 3.1.2 okta-auth-js

The official documentation says about signOut() method:

Signs the user out of their current Okta session and clears all tokens stored locally in the TokenManager. By default, the access token is revoked so it can no longer be used.

After we use signOut() we are still able to receive user data for example using this route
${baseUrl}/v1/userinfo and token that was valid before signOut().

async logout() {
  this.oktaAuth.signOut({
    postLogoutRedirectUri: environment.oktaConfig.postLogoutRedirectUri
  })
  .catch((err) => {
    console.log(err);
  });
}

But when we use revokeAccessToken() inside logout() implicitly it works and userinfo is no longer accessible using accessToken.

async logout() {
  await this.oktaAuth.revokeAccessToken().catch((err) => {
    console.log(err);
  });
  this.oktaAuth.signOut({
    postLogoutRedirectUri: environment.oktaConfig.postLogoutRedirectUri
  })
  .catch((err) => {
    console.log(err);
  });
}

Can you please advice if we are doing something wrong or calling signOut() does not call revokeAccessToken() by design? Thank you.

@shuowu
Copy link
Contributor

shuowu commented Jun 12, 2020

@Taras-R By checking the code in v3.1.2, looks like it behaves as expected.
From what you described, it looks like you may be using version 2 of okta-auth-js, can you please step into the code to see if the signOn method is used from version 3. There may be multiple copies of okta-auth-js in your dependencies tree.

@Taras-R
Copy link
Author

Taras-R commented Jun 15, 2020

@shuowu thak you for your respond.
We never used version 2 in development. We started application with v3.1.1.
Then we updated to v3.1.2 to make sure issue still exist.
We removed all the node_modules and installed them from scratch. Issue still exists.
Packages used.
image
So when using signOut() accessToken is not revoked under the hood and user data still can be accessed. When calling manually revokeAccessToken() before signOut() then token is revoked and data can not be accessed.
Tried the request in Postman during active session and after signOut().

@swiftone
Copy link
Contributor

@Taras-R - Your code sample calling signOut is async, but NOT awaiting the result of signOut, so your logout method completes before the internals of signOut have ever run. If another step running after your logout() modifies token storage or other interactions, the code may be unable to effectively revoke the token when it finally goes to do so.

I suggest:

async logout() {
  await this.oktaAuth.signOut({ // Note the 'await' here
    postLogoutRedirectUri: environment.oktaConfig.postLogoutRedirectUri
  })
  .catch((err) => {
    console.log(err);
  });
}

Let us know if that helps at all.

@Taras-R
Copy link
Author

Taras-R commented Jun 22, 2020

@swiftone thank you for your response! We tried the solution you propose and it still works the same. Token is revoked only when we manually use revokeAccessToken().
Anyway, if it can't be reproduced on your side, we can go with revoking token manually - it works perfect.

@aarongranick-okta
Copy link
Contributor

internal ref: OKTA-308847

@Fusekki
Copy link

Fusekki commented Jul 10, 2020

We are currently experiencing the same issue. Have used both the samples provided in this thread:

async logout() { await this.oktaAuth.revokeAccessToken().catch((err) => { console.log(err); }); this.oktaAuth.signOut({ postLogoutRedirectUri: environment.oktaConfig.postLogoutRedirectUri }) .catch((err) => { console.log(err); }); }

and also

async logout() { await this.oktaAuth.signOut({ // Note the 'await' here postLogoutRedirectUri: environment.oktaConfig.postLogoutRedirectUri }) .catch((err) => { console.log(err); }); }

Neither work in revoking the token after signout. This is a huge issue for us as it is a security threat.

@shuowu
Copy link
Contributor

shuowu commented Jul 10, 2020

@staffordp revoke should be handled by providing a boolean option for the signOut method to trigger the revoke behavior.

var revokeAccessToken = options.revokeAccessToken !== false;

await signOut({ revokeAccessToken: true })

Also, for the first code snippet, okta-auth-js will only look for accessToken (https://github.com/okta/okta-auth-js/blob/master/packages/okta-auth-js/lib/browser/browser.js#L265) from the storage. Please provide the accessToken when calling the revokeAccessToken method if you renamed the storage key in code.

Please see detailed information in revokeAccessToken API

@Fusekki
Copy link

Fusekki commented Jul 10, 2020

@shuowu

After updating to the following version,

+ "@okta/okta-auth-js": "^3.1.4",

I tried this snippet after but it did not work. Do you believe the tokenManager.clear() could have caused an issue?

await this.authClient.tokenManager.clear();

      await this.authClient.signOut({ 

        revokeAccessToken: true

      });

Also, I am not sure why the revokeAccessToken needs to be explicit. The docs on the site say:

signOut()
Signs the user out of their current Okta session and clears all tokens stored locally in the TokenManager. By default, the access token is revoked so it can no longer be used.

@shuowu
Copy link
Contributor

shuowu commented Jul 10, 2020

@staffordp You are right, it does not need to be set explicitly. Sorry, I miss read the code.
Also, signOut will clear tokens by itself ( https://github.com/okta/okta-auth-js/blob/master/packages/okta-auth-js/lib/browser/browser.js#L300 ), so you don't need to handle it explicitly.

Based on the report, looks like there is an issue with revoking the token (I suspect the storage key you use in code may be different with the default storage key, which is accessToken ). The current workaround can be

  1. get the token from the tokenManager.
  2. revoke the token.
  3. call signOut method to close the session.

@Fusekki
Copy link

Fusekki commented Jul 17, 2020

We are using the following code:

 const myAccessToken = this.cookieService.get('accessToken');  
    await this.authClient.revokeAccessToken(myAccessToken)
      .then((res) => {
        this.cookieService.delete('accessToken', '/', '.example.com');
      })
      .catch((err) => {
        console.log(err);
      });
   
      await this.authClient.signOut({
        revokeAccessToken: true
      });

I've tried with both the revokeAcessToken: true and without. Neither work. I am still able to view client info with that same accessToken after this code runs. At this point, I am at a loss as to what to do.
`

@Taras-R
Copy link
Author

Taras-R commented Jul 20, 2020

@staffordp here is piece of code we use and it revokes token manually. The only difference i can tell is that we do not get token with our service but use Okta method (if you saved token in token manager with key 'accessToken' there is no need to get it). So i think you just don't use Okta token manager to save token, but your own service. And i think revokeAccessToken can receive token object, not just raw JWT (documentation still is not very clear about it, it is just telling to provide this token if it was saved in different place and nothing about format).

By default, revokeAccessToken will look for a token object named accessToken within the TokenManager. If you have stored the access token object in a different location, you should retrieve it first and then pass it here.

Here is an example in documentation where they get the token to renew it: https://www.npmjs.com/package/@okta/okta-auth-js?activeTab=readme#tokenrenewtokentorenew (it is an object received from Okta, not just string). Hope that helps, try to save token using token manager and it should work.

this.oktaAuth.tokenManager.add('accessToken', response.tokens.accessToken);

and this

async logout() {
    await this.oktaAuth.revokeAccessToken();
    return this.oktaAuth.signOut({
      postLogoutRedirectUri: environment.oktaConfig.postLogoutRedirectUri
    });
  }

I still don't understand why it does not work from the box as it is described in documentation, especially when lot of users even have no idea that after using signOut their token is not revoked. After this code runs user info is not accessible anymore.

@Fusekki
Copy link

Fusekki commented Jul 20, 2020

@Taras-R

If I need to pass the accessToken object, or I need to populate it in the tokenManager, what format should it be in?

We have a situation where the user uses an Angular app just to handle the login and Okta token retrieval. It stores the values of the idToken and accessToken (the value string), and full accessToken object in different cookies and redirects to another Angular app where these cookies are used for calls.. On logout, the user is redirected to the Login app's logout component where it attempts to sign the user out. I am assuming this tokenManager is cleared between these app loads. So, if this is the case and I am unable to retrieve that token via tokenManager at first, how can I either repopulate it into the tokenManager in a format that it is friendly to it (via a cookie) or convert it and pass it directly into the revokeAccessToken() call?

Edit: Also, I was not able to successfully attempt to revoke the token seeing how the call always redirected me to the 400 Okta Page citing a non-white listed redirect URI when in fact I was passing in one that was. Even when omitting the postLogoutRedirectUri, I still am redirected to the 400 page with the latest 3.14 version. I tried making a few API calls after to see if the accessToken had been revoked even though experiencing the 400 page, but found I was still able to successfully make POST calls with that same accessToken.

@Taras-R
Copy link
Author

Taras-R commented Jul 21, 2020

If you have all token object saved, i think it should work, token manager just saves it and allows to access it quickly. Just try raw JWT and also try object returned with Okta, i didn't analyze source code so i'm not sure which one is correct.

In every angular app you must create new OktaAuth() to access all methods in any of them (signOut and revokeAccessToken). Applications should share same domain, so cookies can be shared too. Link you use to redirect after logout must be provided in logout redirect uri's list in settings of your Okta application. If it is not provided, Okta will show you error page that url is not whitelisted.

@Fusekki
Copy link

Fusekki commented Jul 21, 2020

@Taras-R

If you have all token object saved, i think it should work, token manager just saves it and allows to access it quickly. Just try raw JWT and also try object returned with Okta, i didn't analyze source code so i'm not sure which one is correct.

In every angular app you must create new OktaAuth() to access all methods in any of them (signOut and revokeAccessToken). Applications should share same domain, so cookies can be shared too. Link you use to redirect after logout must be provided in logout redirect uri's list in settings of your Okta application. If it is not provided, Okta will show you error page that url is not whitelisted.

I tested out again this morning without even moving between different apps by running it local. I am still unable to revoke the token (after this code executes, I am still able to make API calls using that same accessToken value). Additionally, on sign out, I keep getting redirected to the followiing page (attached), even though the domain(s) I have tried are all whitelisted in the Okta app for Login redirect URIs. Here is the code I am using below:

in the constructor for the Okta client creation:

    this.authClient = new OktaAuth({
      clientId: this.appConfig.getConfig('oktaClientId'),
      issuer: this.appConfig.getConfig('oktaUrl'),
      authorizeUrl: `${this.appConfig.getConfig('oktaUrl')}/v1/authorize`,
      redirectUri: this.appConfig.getConfig('oktaRedirectUri'),
      tokenManager: {
        storage: 'sessionStorage'
      },

SignOut:

  async signOut() {
      await this.authClient.revokeAccessToken(); // strongly recommended
      return this.authClient.signOut({
        postLogoutRedirectUri: this.appConfig.getConfig('oktaRedirectUri'), // **this URI is whitelisted in Login redirect URIs**
      });
 }

I don't understand why it is NOT revoking the token even though I am running 3.14 and I am following all documentation and suggestions. Further, if the URI is whitelisted, WHY does it keep giving me this error?

okta-error-screen

@Taras-R
Copy link
Author

Taras-R commented Jul 21, 2020

@staffordp i'm not Okta developer, and i would answer if i wrote this code:) i'm just the one who started this conversation. I agree it MUST work, but it is not. My solution with revoking manually works fine as i can tell. In your config i see difference with ours: postLogoutRedirectUri, not just redirectUri

@Fusekki
Copy link

Fusekki commented Jul 21, 2020

@Taras-R

Would you mind sharing your oktaConfig? Perhaps with the upgrade from 2.9, some of the options we are specifying in the config are old and causing this issue?

@Taras-R
Copy link
Author

Taras-R commented Jul 21, 2020

it's pretty much default

issuer: '',
clientId: '',
redirectUri: '',
postLogoutRedirectUri: '',
responseType: ['id_token', 'token']

@Fusekki
Copy link

Fusekki commented Jul 21, 2020

@Taras-R

Thanks for sharing. I thought perhaps you had a config item I was missing that may have led to my problem but it doesn't seem so.

@swiftone
Copy link
Contributor

@staffordp - We've noticed issues where the browser might append/remove a trailing / on the url compared to the value stored in Okta. If you have a redirect_uri that you think should be working, try adding versions both with and without a trailing slash to see if that clears anything up.

We're testing different browsers to see if we can get the exact symptoms down. I'm not sure if this is related to your issue or not, but worth checking.

@Fusekki
Copy link

Fusekki commented Jul 27, 2020

@swiftone

Thanks for the reply. I had originally read the documents wrong and didnt realize there was a section for Logout Redirect URIs which we did not have populated. Once we added the URIs there, the issue with redirecting to the Okta page went away.

@Fusekki
Copy link

Fusekki commented Jul 28, 2020

@swiftone Was also able to validate via Okta support that the token is being revoked properly. The issue is with our API library not checking for revocation.

@swiftone
Copy link
Contributor

@Taras-R - We've identified a bug in the signOut method that will break revoke. Fix incoming soon.

Internal ref: OKTA-315806

@hicaro
Copy link

hicaro commented Jul 30, 2020

I was going through the same problem. I observed that within the signOut function it is trying to retrieve the accessToken
from the token manager using the property name token. This already might be the bug @swiftone has described.

accessToken = await sdk.tokenManager.get('token');

The work around for me was to provide the accessToken in the options:

await this._oktaAuth.signOut({
  revokeAccessToken: true,
  idToken,
  accessToken
});

@swiftone
Copy link
Contributor

@hicaro - nice workaround! Yes, that was the bug (already fixed but not yet released here: #436)

@shuowu shuowu closed this as completed Sep 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants