-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Refresh tokens need a grace period to deal with network errors and similar issues #1831
Comments
This is currently not possible, the client would need to talk to |
@aeneasr does it help to mitigate the replay attack if we set a low default before the old token is completely unusable. And to avoid exploding the amount of token issued, we could return the same token that was lost during the network error. Please, just correct me if I'm wrong. |
Lowering TTL of things is typically a good guard against replayability, but doesn't resolve it completely of course :)
While this is a valid strategy and also supported by some servers, it does not work in ORY Hydra. We do not store the full access tokens in the database but instead generate it from a strong This feature prevents anyone with database access from issuing access and refresh tokens without also having access to the ORY Hydra |
I am marking this issue as stale as it has not received any engagement from the community or maintainers in over half a year. That does not imply that the issue has no merit! If you feel strongly about this issue
We are cleaning up issues every now and then, primarily to keep the 4000+ issues in our backlog in check and to prevent maintainer burnout. Burnout in open source maintainership is a widespread and serious issue. It can lead to severe personal and health issues as well as enabling catastrophic attack vectors. Thank you for your understanding and to anyone who participated in the issue! 🙏✌️ If you feel strongly about this issues and have ideas on resolving it, please comment. Otherwise it will be closed in 30 days! |
Closed in error |
This issue also prevents Ory Hydra from being used in a clustered environment without added complexity, as mentioned in this issue: ory/fosite#255 also see: https://datatracker.ietf.org/doc/html/rfc6819#section-5.2.2.3
If two concurrent processes both attempt to refresh the token simultaneously one will always fail. This means either adding a global mutex to prevent concurrent refresh requests or adding retries. The mutex solution means more ops and hurts scalability while the retry solution adds complexity to the client code and creates a bunch of false-positive auth errors in logs. A grace period would allow some hysteresis that would just need to last enough time to cover the "read token, check if expired, refresh token" code. Auth0 and Okta solve this with a per-client configurable option to disable refresh token rotation entirely. An option to add a grace period would be even better. |
Just to add another perspective here, maybe instead of using a grace period, idempotency keys is what should be implemented instead. That is not covered by any OpenID Connect standard though (there is a standardization draft for the header itself though), but it could be an opt-in extension, if you use idempotency key header, then you enable this behavior. An interesting thing about idempotency keys is that it is done at an API layer and would not require underlying changes to Fosite/Hydra storage. |
Thank you for the idea - the concept looks really interesting. I'm not sure if it addresses the issue we have here though. The proposed standard prevents resending the same payload twice, as the idempotency key will only allow one request to pass. We do have an idempotency key already! It's the refresh token! If you re-use the refresh token, the request fails. The problem described here is that we want to be able to reuse the refresh token in certain scenarios. This might be the case in distributed applications, where it is difficult to get a shared state due to eventual consistency. Another example is that we have a race condition and send the same refresh token (idempotency key) twice, which ends up in rejecting the second request, and - following OAuth2 best practices - invalidates the refresh keys. Hope this makes sense! |
It seems like Google expects the old refresh token to keep working until "they have sent a request using the new token". From Google Smart Home Test Suite Refresh Token Validation Test (emphasis mine):
After this test fails the account link becomes broken. I can only assume Google threw away the new refresh token because of the test failure and it would use the new token under normal circumstances. More on account linking. Google's OAuth2 implementation allows up to 50 refresh tokens to be valid concurrently. That's a lot of tokens and I'm not sure how they implement token reuse detection but I'm afraid having more than one valid refresh token at any given time may be required to avoid account link breakage. |
That only works if your infrastructure uses the introspection endpoint at Ory Hydra. That will often not be the case, especially when people use the JWT strategy. I think the grace period should sufficiently deal with this problem :) |
But I think they have a point. I think the best combination would be:
So I think grace period works for the worst case, but for the one common case (when you do use introspection endpoint) we can increase security by invalidating early. So I do not think we loose anything by adding logic to introspection endpoints to invalidate old refresh tokens when they get a call associated with the new one. |
I think it is the opposite: it allows multiple requests to have the same successful response, but it is only once acted on the request: other times it just returns recorded response for the first successful request.
This is exactly the opposite of what the idempotency keys provide. The behavior should be something like:
|
I think that could be a problem for clients running on "eventually consistent" databases. For instance, the Google Identity documentation, specifically states:
So the Google Smart Home Test Suite Refresh Token Validation Test recommendation of invalidating the old token as soon as you notice a request using the new token is actually in contradiction with this 🤷♂️ Speaking of that test, I can see the refresh token grace period feature from #2827 makes it pass, which is awesome, but still, if for whatever reason token reuse detection does kick in, without an alternative refresh token, I suppose the issue with the account link breaking would still occur. Anyway I believe I'm drifting further away from the issue subject so I've opened a discussion if anyone is interest in continuing this conversation: #2946 |
@yangm97 In my understanding, we need to wait for #2827 to be released, but do you have any workaround in your mind? |
@tommyasai I built a docker image from the source code of #2827 (HEAD was e992907 at that time). If you just need to test something quick and don't mind running a stale version of that PR (nor running binaries from strangers on the internet 😅) then sure I could push that docker image somewhere public. If you intend to run this on production and are not comfortable enough with the codebase to compile a version yourself I would advise against running off tree. As a general rule, you're almost always guaranteed to get undocumented breaking changes which may be as easy to fix as running the down migration(s) from previous iterations and then applying the newer ones or in the worst case you might need to patch your way out a situation nobody else has been before. Scary. PS: you can also find me on telegram, same username as here. While it is good to know people on the same boat as us I think we should avoid stealing the thread heh |
@yangm97 We still have some time till the actual release for users, so as a workaround for production, we are also thinking about implementing the proxy to cover the functionality. |
Just a quick question : I'm using Hydra in production on a 3 site cluster with JWT and access_token lifespan of 5m to easily revoke accesses in case of compromise. And in 1 week of usage on our Drive Sync Client on 30 beta testers, 2 clients already lost the new tokens due to crashes at the wrong moment or the os killing the app at shutdown. |
Yes but it’s very difficult to implement securely |
Hello contributors! I am marking this issue as stale as it has not received any engagement from the community or maintainers for a year. That does not imply that the issue has no merit! If you feel strongly about this issue
Throughout its lifetime, Ory has received over 10.000 issues and PRs. To sustain that growth, we need to prioritize and focus on issues that are important to the community. A good indication of importance, and thus priority, is activity on a topic. Unfortunately, burnout has become a topic of concern amongst open-source projects. It can lead to severe personal and health issues as well as opening catastrophic attack vectors. The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone. If this issue was marked as stale erroneously you can exempt it by adding the Thank you for your understanding and to anyone who participated in the conversation! And as written above, please do participate in the conversation if this topic is important to you! Thank you 🙏✌️ |
This issue is not stale |
I was waiting on an input on #2827 regarding code reuse, to know if I can adapt the code to hydra v2. |
@aeneasr Would more/different work from the community be helpful here at the moment? And do you think this issue will be a priority in the near future? - Not meant to put any pressure on you. We're just discussing whether to wait on this or change quite a few things on our end to solve our problems; and would be grateful for a quick update 🙏 We don't have any Go programmers on the team, but are happy to help where we can (documentation, test cases?, ...) |
This patch adds a configuration flag which enables graceful refresh token rotation. Previously, refresh tokens could only be used once. On reuse, all tokens of that chain would be revoked. This is particularly challenging in environments, where it's difficult to make guarantees on synchronization. This could lead to refresh tokens being sent twice due to some parallel execution. To resolve this, refresh tokens can now be graceful by changing `oauth2.grant.refresh_token.grace_period=10s` (example value). During this time, a refresh token can be used multiple times to generate new refresh, ID, and access tokens. All tokens will correctly be invalidated, when the refresh token is re-used after the grace period expires, or when the delete consent endpoint is used. Closes #1831 #3770
This patch adds a configuration flag which enables graceful refresh token rotation. Previously, refresh tokens could only be used once. On reuse, all tokens of that chain would be revoked. This is particularly challenging in environments, where it's difficult to make guarantees on synchronization. This could lead to refresh tokens being sent twice due to some parallel execution. To resolve this, refresh tokens can now be graceful by changing `oauth2.grant.refresh_token.grace_period=10s` (example value). During this time, a refresh token can be used multiple times to generate new refresh, ID, and access tokens. All tokens will correctly be invalidated, when the refresh token is re-used after the grace period expires, or when the delete consent endpoint is used. Closes #1831 #3770
This patch adds a configuration flag which enables graceful refresh token rotation. Previously, refresh tokens could only be used once. On reuse, all tokens of that chain would be revoked. This is particularly challenging in environments, where it's difficult to make guarantees on synchronization. This could lead to refresh tokens being sent twice due to some parallel execution. To resolve this, refresh tokens can now be graceful by changing `oauth2.grant.refresh_token.grace_period=10s` (example value). During this time, a refresh token can be used multiple times to generate new refresh, ID, and access tokens. All tokens will correctly be invalidated, when the refresh token is re-used after the grace period expires, or when the delete consent endpoint is used. Closes #1831 #3770
So basically, on Hydra if the refresh token is already used to request for a new set of tokens, that refresh token is invalidated and can't be used to request for a new set of tokens. It's a one time use only.
At the event, where the tokens were actually issued by Hydra but the response was not sent to the users because of some network issues, the users are generally stuck. Is there a way for us to not invalidate the refresh token immediately and have a refresh token grace period to perform a duplicate refresh requests with the same refresh token.
The text was updated successfully, but these errors were encountered: