Skip to content

Multi-session user login impossible: cross-context (API+UI) refresh token invalidation #3525

Closed
@mattsmithies

Description

@mattsmithies

Problem description

This is a bug which has been frustrating the heck out of me that is related to the 2.18.0 release, and I can finally articulate what is going on!

Consider, a situation where you are in parallel experimenting/testing with guardian on the UI and API (or different browsers)

As per the new authentication measures in 2.18.0 there is a hard requirement for the generation of a refresh token before the access token can be created.

There is an issue where that is problematic.

If you are generating new refresh tokens through the API (or potentially in a different browser) the old refresh token loses the ability to generate new access tokens.

A screenshot from the policies view:

Screenshot 2024-04-11 at 08 42 30

This basically happens under the conditions:

  • Multiple refresh tokens are generated under different context
  • The last refresh token has context to the user object
  • (For UI token) After default access token timeout of 60 seconds a new access token can't be generated as the previous refresh token has been overwritten.

This is because of these lines

https://github.com/hashgraph/guardian/blob/main/auth-service/src/api/account-service.ts#L156

This is exacerbated due to this line:

https://github.com/hashgraph/guardian/blob/main/auth-service/src/api/account-service.ts#L185

As the filter is looking for both the username, and the refresh token id (that may not exist on the user object due to it being overwritten)

Step to reproduce

Steps to reproduce the behavior:

  1. UI Login as user
  2. Use API to login as same user (or potentially different browser)
  3. Wait 60 seconds
  4. See DID missing error

Expected behavior

Looking into the code, it seems that the refresh token should last for a year, this is fine as it is configurable, but losing login context (or a user potentially feeling they lost all their data) isn't great UX.

In terms of code behaviour, I would presume that this change would fix the issue:

const user = await new DataBaseHelper(User).findOne({refreshToken: decryptedToken.id, username: decryptedToken.name});

to

const user = await new DataBaseHelper(User).findOne({username: decryptedToken.name});

The reason why this might be okay, is that the expire at decoding happens on the line above, so a refresh token, would last for the period of time by default.

As this is authentication related, it requires review from more people.

More context

I am unsure to whether this could be related to this issue #3450, as the lock up of the system could be related to a invalid access, token that is in an infinite loop state.

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions