-
-
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
feat: Refresh token expiration window #2827
feat: Refresh token expiration window #2827
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good :) Could you please also add some docs for this? :)
create migrations with command: ory dev pop migration create persistence/sql/migrations/ add_refresh_token_used_flag
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, I've got a couple of questions and ideas :)
persistence/sql/migrations/20211101093405_add_refresh_token_used_flag.up.sql
Outdated
Show resolved
Hide resolved
persistence/sql/persister_oauth2.go
Outdated
@@ -280,13 +325,27 @@ func (p *Persister) deactivateSessionByRequestID(ctx context.Context, id string, | |||
return sqlcon.HandleError( | |||
p.Connection(ctx). | |||
RawQuery( | |||
fmt.Sprintf("UPDATE %s SET active=false WHERE request_id=?", OAuth2RequestSQL{Table: table}.TableName()), | |||
fmt.Sprintf("UPDATE %s SET active=false, used=true WHERE request_id=?", OAuth2RequestSQL{Table: table}.TableName()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we actually need used
when we have active
already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, findSessionBySignature
will return errors when a session is marked inactive.
persistence/sql/persister_oauth2.go
Outdated
|
||
if ! used { | ||
session := requester.GetSession() | ||
session.SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(gracePeriod)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So to understand this a bit better - when refreshing a token we do not deactivate it (active: false
) immediately. Instead, if grace is enabled, we extend the expiry time by X from NOW, and we also set used: true
. The next time we refresh the token, and we are still in the refresh grace period, nothing is updated.
When we refresh the token again, and NOW + x has passed, fosite will see the key as expired, implying that it is no longer active.
I think this has some serious implications. I am not 100% any more how token reuse detection works, but I think it doesn't trigger on expired tokens, only on inactive ones. Because an expired token has not been reused, it just expired! And since it's expired, you can't use it. A used (active=false) token though has been used, thus, reuse means invalidation of all other tokens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're saying
- this will work but the error will be wrong (expired not reused)
- when reused and expired, since it isn't detected as reused other tokens are not revoked
I mentioned in an earlier comment that setting active=false
won't work for grace periods, since calls to findSessionBySignature
will not succeed. To properly detect that case (active==true, in_grace_period==true, expired
) something could be modified to deal with it, I'm worried that changing findSessionBySignature
to throw an expired error may have undesirable repercussions. From what I can tell token validation, which includes expiration checking, is done at a different layer and is part of a Strategy. The persistence layer does not have access to token strategies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was what I was trying to say :)
The best way to prove/disprove this hypothesis is to introduce a test which covers this. If there's no regression on revokation, this should be fine! It would theoretically also be fine to revoke the token chain on expiration also, not just on reuse.
Co-authored-by: hackerman <3372410+aeneasr@users.noreply.github.com>
use reflection to control configuring the persister during tests
Is this good for another review @bill-robbins-ss ? :) |
@bill-robbins-ss I fixed the conflicts and got parts of the CI to pass again, however there seems to be an linting issue. Would it be possible for you to take a look? ps: For motivation, we have merged several large-scale changes to Ory Hydra so there's a good chance this will land very quickly as well :) |
@aeneasr this is great, I'll be checking it out this week hopefully getting those rules to pass. Do you know how releasing will be done? We'll want to upgrade our instance to take advantage of the great new things! |
Once this is merged we'll do a new minor release |
hey @aeneasr I fixed the linting errors that came from me, but he other 3 are on code that I didn't touch. Please advise. |
…ation-window # Conflicts: # CONTRIBUTORS # docs/docs/guides/token-expiration.mdx # docs/docs/reference/configuration.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the work and sorry for the late review time. I did fix some things in the PR but while working on it, I realized that there is still some way to go. In particular:
- The new
in_grace_period
column breaks all tables that do not have this column as they all re-use the same struct to load stuff from the database - The feature is not end-to-end tested
- Documentation is missing
Given the sensitivity of this feature we need to ensure that everything works end-to-end. So:
- Refreshing a token within the grace period works
- Revoking a token revokes also all grace tokens
- Rotating a grace token works and does not affect other tokens
- Token reuse still works after grace period and revokes all of those tokens also
Let me know if you need any help with this!
Hey @aeneasr thank you for checking in on this.
Also, I saw that you removed the |
Thank you @bill-robbins-ss for the fast response and keeping engaged. I have this PR on my prio list now and will be more active reviewing it. You can also ping me on Slack if I am too slow :) Regarding your questions:
It does! I would encourage you though to maybe rebase this PR right away with #2796 to avoid any big conflicts during merge.
Exactly, I would suggest to cover the following use cases:
We also need to cover revokation and deleting the consent:
Checking whether we can refresh graceful tokens is important too:
As well as introspection:
I believe most functions are there already to test this, so it should not be too much work hopefully. Besides e2e tests, it probably also makes sense to start with some Go test first, as that will make debugging so much easier for you! hydra/oauth2/oauth2_auth_code_test.go Line 277 in 8a966e8
Apologies, I got in review mode and am not fully used to the new docs system yet 😓
Yes, it's now defined on the interface level so no reflection is needed! |
@bill-robbins-ss please let me know when you think that this is good for another review :) |
Hi, any update here? Is configuration described here https://www.ory.sh/docs/hydra/guides/token-expiration#refresh-token-rotation ready for using? |
Looks like that made it to prod on mistake, the feature is not yet usable! |
@aeneasr thank you for your reply! I really need feature like this. We use hydra in our project and it works well. But now we want to connect to google assistant by account linking. There is a problem with the refresh token rotation. The error from google like this: |
Hi @aeneasr and @bill-robbins-ss ! Is this feature something scheduled and that we may expect in a near future? |
Hi @aeneasr, I am willing to continue the work on the coming months as we are currently experiencing network token loss when Windows goes to sleep with our app and also with our android / ios app. Did @bill-robbins-ss signed the Ory Code Agreement so that I can reuse his code and pursue the implementation ? Kind regards, |
The issue was closed because the original fork was mistakenly deleted. I created a new fork and pushed the branch, but it would not let me push to the same branch name, so it is now at https://github.com/shipstation/hydra/tree/refresh-token-expiration-window-2. Unfortunately, there does not appear to be a way to change the branch for this PR to reference the new branch. Either way, it looks like the code is still accessible in this PR - maybe an ory/hydra project owner can re-open the PR |
oauth2.refresh_token_rotation.grace_period
that can be set as a duration (1m
,used
SQL column inhydra_oauth2_refresh
When
grace_period
has positive duration the act of using a refresh token will not invalidate the token and instead mark it as used in the database and set its expiration time to the UTCNOW + the value of the grace period. This will allow a client to continue to use a refresh token for the duration of the grace period.Related issue(s)
#1831
Fosite 255
introduces a new feature.
contributing code guidelines.
vulnerability. If this pull request addresses a security. vulnerability, I
confirm that I got green light (please contact
security@ory.sh) from the maintainers to push
the changes.
works.
Further Comments
This change includes a modification to Fosite in PR 634