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

feat: Token refresh hook #2649

Merged
merged 6 commits into from
Sep 1, 2021
Merged

feat: Token refresh hook #2649

merged 6 commits into from
Sep 1, 2021

Conversation

svrakitin
Copy link
Contributor

@svrakitin svrakitin commented Jul 23, 2021

  • Add oauth2.refresh_token_hook to configure an endpoint which will be called during refresh_token grant to retrieve updated token claims. Hook will be noop if not configured.
  • Add AccessRequestHook interface and RefreshTokenHook implementation.

Related issue(s)

#2570

Checklist

Further Comments

I added github.com/hashicorp/go-cleanhttp as a dependency, but I can avoid it if necessary.

Copy link
Member

@aeneasr aeneasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great, I think a few more tests and a bit of config changes and we can merge this! Sorry for the late review :)

oauth2/oauth2_auth_code_test.go Outdated Show resolved Hide resolved
spec/config.json Outdated Show resolved Hide resolved
oauth2/oauth2_auth_code_test.go Outdated Show resolved Hide resolved
t.Skip()
}

hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add tests:

  1. Where the server responds with a non-ok status code
  2. Where the server responds with malformed (e.g. empty / unset / incorrect) payloads

Thank you :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added more tests.

oauth2/hook.go Show resolved Hide resolved
docs/docs/advanced.md Outdated Show resolved Hide resolved
@svrakitin
Copy link
Contributor Author

@aeneasr Thanks for the comments, I will update the PR this week.

@svrakitin
Copy link
Contributor Author

Updated PR. Some tests seem flaky.

@svrakitin svrakitin requested a review from aeneasr August 6, 2021 13:32
@codecov
Copy link

codecov bot commented Aug 17, 2021

Codecov Report

Merging #2649 (96324ae) into master (336afa0) will increase coverage by 0.12%.
The diff coverage is 69.86%.

❗ Current head 96324ae differs from pull request most recent head df008a2. Consider uploading reports for the commit df008a2 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2649      +/-   ##
==========================================
+ Coverage   52.68%   52.80%   +0.12%     
==========================================
  Files         234      235       +1     
  Lines       14040    14113      +73     
==========================================
+ Hits         7397     7453      +56     
- Misses       6016     6029      +13     
- Partials      627      631       +4     
Impacted Files Coverage Δ
oauth2/hook.go 63.93% <63.93%> (ø)
driver/config/provider.go 88.99% <100.00%> (+0.10%) ⬆️
driver/registry_base.go 89.28% <100.00%> (+0.21%) ⬆️
oauth2/handler.go 68.19% <100.00%> (+1.18%) ⬆️
persistence/sql/persister_oauth2.go 82.86% <0.00%> (+0.79%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 336afa0...df008a2. Read the comment docs.

@svrakitin
Copy link
Contributor Author

@aeneasr Please review when you've got time, don't want to leave this hanging.

aeneasr
aeneasr previously approved these changes Sep 1, 2021
Copy link
Member

@aeneasr aeneasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thank you! 🎉

docs/docs/advanced.md Outdated Show resolved Hide resolved
@aeneasr aeneasr merged commit 1a7dcd1 into ory:master Sep 1, 2021
@svrakitin svrakitin deleted the token-refresh-hook branch September 1, 2021 06:36
@alee792
Copy link

alee792 commented Oct 12, 2021

Apologies if this isn't the right place, but could this hook be extended to update consent/OIDC claims like ACR and AMR? This could support step-up or forced re-authn.

For example, a user logs in with basic credentials and the identity provider's initial flow grants an id_token with an ACR indicating AAL1. Later out-of-band, the identity provider solicits additional factors without going through the auth code grant again. When queried, the IDP can return those new ACR and AMR values.

If the RefreshHookResponse included these "non-Extra" fields, we could strengthen or modify the authenticator assurance level of the token's session. These fields are already delegated to the identity provider and taken at face value by Hydra.

@svrakitin
Copy link
Contributor Author

svrakitin commented Oct 12, 2021

@alee792 Yeah, makes sense to me, will figure out how to plug it in in spare time and see how it works.

I am just not sure if it is not confusing to the consumer if the ID Token. I would probably allow setting ACR, but not AMR, as AMR actually tells you original method of authentication used. We should either append new AMRs or pass original AMRs in hook request so you handle the merge.

You will also probably need a sid claim to link upgraded authentication to the refresh. Would you implement any kind of token binding to ensure that upgraded token can only be used by an actual user?

Ideally your authentication always goes through identity provider through auth code grant or you use some custom grant for that instead of such adhoc scheme.

@alee792
Copy link

alee792 commented Oct 13, 2021

Good point on AMR. I'm skimming through RFC8176 and this seems to be their overarching guidance:

Parties using this claim will need
to agree upon the meanings of the values used, which may be
context-specific.

With this in mind, we may want to just keep it as malleable as possible. It's a bit contrived, but imagine there's a forced re-authn event where the user authenticates with an entirely different set of factors. The original factors lose significance and it could be unnecessary to keep them. As the RFC suggests, that meaning is up to the CSP and RP to decide.

Would you implement any kind of token binding to ensure that upgraded token can only be used by an actual user?
I don't think Hydra can enforce the binding, but SessionID could be added to the RefreshHookRequest for the IDP to resolve a session.

Your last point makes sense as well. If the IDP is maintaining it's own cookie-based session, the RP could just go through the auth code grant for step-up or reauthn. It's a bit more chatty going through the entire flow again, but there's less risk of skew.

@kszafran
Copy link

@svrakitin I just noticed that this feature was released in v1.10.7. I'm trying to understand -- does this hook get called also on the initial flow, when the caller gets the access token for the first time? If not, is there already a way to customize access token claims with hooks during the initial flow?

@svrakitin
Copy link
Contributor Author

@kszafran You pass initial claims when you accept consent request. Hook is only triggered on refresh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants