ory / hydra

The most scalable and customizable OpenID Certified™ OpenID Connect and OAuth Provider on the market. Become an OpenID Connect and OAuth2 Provider over night. Broad support for related RFCs. Written in Go, cloud native, headless, API-first. Available as a service on Ory Network and for self-hosters.
https://www.ory.sh/?utm_source=github&utm_medium=banner&utm_campaign=hydra
Apache License 2.0
15.52k stars 1.49k forks source link

No support for refresh_token without offline_access scope #2477

Closed synclpz closed 2 years ago

synclpz commented 3 years ago

Describe the bug

No refresh_token is issued if consent flow does not add offline/offline_access scope. There's no way to refresh an access token for SPA without using kinda 'deprecated' prompt=none flow.

Reproducing the bug

Steps to reproduce the behavior:

  1. Run 5-minute tutorial (https://www.ory.sh/hydra/docs/5min-tutorial) -- OAuth 2.0 Authorization Code Grant
  2. After redirection to consent page do not select "offline" checkbox
  3. Resulting page does not show any refresh_token

Expected behavior

An app receives refresh_token without issuing offline_access scope from consent app, but a refresh flow is only available for the client while user is "online" -- thus having an active session on OP (Hydra). When the session expires an attempt to use refresh_token should fail.

Environment

Additional context

SPA with refresh_token described by Auth0: https://auth0.com/blog/securing-single-page-applications-with-refresh-token-rotation/

aeneasr commented 3 years ago
  1. offline_access is an OpenID Connect standard - removing it would break certification. The current behaviour is correct.
  2. The linked blog post explains something unrelated - refresh token rotation and refresh token reuse detection. Both of which are supported by Ory Hydra.
synclpz commented 3 years ago
  1. I do not request removal of offline_access support and hence breaking the certification, of course!
  2. The linked blog post explains the need for refresh tokens in an SPA

From OIDC Core:

offline_access
        OPTIONAL. This scope value requests that an OAuth 2.0 Refresh Token be issued that can be used to obtain an Access Token that grants access to the End-User's UserInfo Endpoint even when the End-User is not present (not logged in).
The use of Refresh Tokens is not exclusive to the offline_access use case. The Authorization Server MAY grant Refresh Tokens in other contexts that are beyond the scope of this specification.

So this issue may be converted to a feature request in case that is not yet implemented. I just thought it's a bug. I expected to receive refresh_token NOT ONLY for offline access.

aeneasr commented 3 years ago

I see, but I don't understand the problem. When would you not be able to send that scope along in the request? Using an SPA does not prevent you from adding offline_access to the list of the requested scopes.

synclpz commented 3 years ago

At the moment getting a refresh token allows SPA to indefinitely, regardless of login/consent expiration, have access to my API or (in case of token misuse/XSS in SPA) allows adversary to have access not from SPA. What I need is to limit refresh-ability to user session on Hydra, thus not offline, but online access.

aeneasr commented 3 years ago

I see - so you want the refresh token only to be granted as long as the user is signed in in Ory Hydra? Are you looking at a first-party use case for your SPA?

svrakitin commented 3 years ago

This would be a really interesting and useful feature not covered by spec. Something like online_access granted scope which we can handle in /oauth2/token handler, before calling fosite. There we could compare sid of the refresh token with the sid value of oauth2_authentication_session cookie.

synclpz commented 3 years ago

Are you looking at a first-party use case for your SPA?

This could be either first- or third-party case, the main point is that SPA developer is not trusted to be careful enough with indefinitely refreshable token, because current Hydra's behavior is to grant access via refresh token even if user consent is expired. I'd rather made offline_access allowed until consent is expired and online_access allowed until login is expired.

compare sid of the refresh token with the sid value of oauth2_authentication_session cookie.

If cookie in DB is not expired

aeneasr commented 3 years ago

I'd rather made offline_access allowed until consent is expired and online_access allowed until login is expired.

So in Ory Hydra it's not easy to tell when the login is invalid and we also do not track what tokens have been issued by what sessions. So this is significant work plus online_access scope is nothing I have encountered in the wild yet - meaning it is something specific to Ory Hydra and not "common practice".

Instead I would propose that we allow you to configure if the refresh tokens should have a rolling expiry window (so every new refresh token resets the expires at time) or if it is a fixed point in time (this you describe in your other issue). This would be configured in your configuration file.

That would be much easier to implement and has sort of the same effect.

Regarding the use of refresh tokens for keeping track of a "session state" - this is in my opinion bad practice and we explain this in depth on this docs page: https://www.ory.sh/hydra/docs/concepts/before-oauth2#access-and-refresh-tokens-are-not-sessions

synclpz commented 3 years ago

Instead I would propose that we allow you to configure if the refresh tokens should have a rolling expiry window (so every new refresh token resets the expires at time) or if it is a fixed point in time (this you describe in your other issue). This would be configured in your configuration file.

I'd prefer to submit a "rolling and window size" or "fixed time exactly YYYY-MM-DD..." through PUT on consent endpoint if it is possible

Regarding the use of refresh tokens for keeping track of a "session state" - this is in my opinion bad practice and we explain this in depth on this docs page: https://www.ory.sh/hydra/docs/concepts/before-oauth2#access-and-refresh-tokens-are-not-sessions

I read this of course, but I think this would become not so true as the approach of using refresh_tokens in SPA instead of silent refresh (prompt=none) becomes more adopted.

aeneasr commented 3 years ago

I read this of course, but I think this would become not so true as the approach of using refresh_tokens in SPA instead of silent refresh (prompt=none) becomes more adopted.

Silent refresh is on the way out as it relies on iframes, which does not work well cross-domain - one of the major reasons for using OpenID Connect!

I'd prefer to submit a "rolling and window size" or "fixed time exactly YYYY-MM-DD..." through PUT on consent endpoint if it is possible

That might also be a possibility!

synclpz commented 3 years ago

Silent refresh is on the way out as it relies on iframes, which does not work well cross-domain - one of the major reasons for using OpenID Connect!

This is exactly what I was talking about :) We need kind of an alternative to prompt=none, which is described in this issue: an approach to use "online" sessions with the OP.

bigred8982 commented 3 years ago

Okta has attempted to address the recent crack-down on 3rd party cookies (which prevents using an iframe to refresh the user session if your idp is 3rd party) with a new feature called Refresh Token Rotation.

https://developer.okta.com/docs/guides/refresh-tokens/refresh-token-rotation/

How it works is that they will let a SPA application ask for and get a refresh token (this is generally frowned upon). The token is essentially a one-time-use refresh token. This solves the problem for SPA app developers as they can refresh the user session / access token very easily.

To counter-act the security concerns, Okta attempts to detect token replay. So, if a bad actor steals one of these refresh tokens, they will attempt to use it to gain an end-user's access_token. Okta detects that the refresh token is being replayed and assumes there is a security breach, at which point it will invalidate the single live refresh token and the user will be required to revalidate their session via a standard redirect mechanism.

This is their approach to the security limitations related to SPA/public clients. I don't know if this information is helpful, but the solution sounds interesting.

aeneasr commented 3 years ago

Thank you @bigred8982 - this is essentially what Ory Hydra is capable of since several years. You can use authorize code with public clients in Ory Hydra. Refresh tokens are one time use and we have strict anti-replay policies in place.

github-actions[bot] commented 2 years ago

Hello contributors!

I am marking this issue as stale as it has not received any engagement from the community or maintainers 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 erroneous you can exempt it by adding the backlog label, assigning someone, or setting a milestone for it.

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 🙏✌️