Messages - 0. Add scope for offline access

Issue #539 resolved
Nat Sakimura
created an issue

We have not defined whether the access_token should be session bound or long lived. We have not defined how to ask for refresh token.

Unless we define them, there will be non-interoperable solutions everywhere.

Default should also be defined.

Suggested default: if it were code flow, then refresh token is issued. If it were token flow, no refresh token is issued. * If refresh token is issued, it is valid until revoked.

Comments (12)

  1. Michael Jones

    When an access token expires OAuth returns a 401. Clients already have to be able to handle this. Some implementations have objected to the specs potentially injecting themselves into their risk analysis.

    A related discussion is how auto-approval should work and what we need to specify about it. We also may want a means of requesting a refresh token.

    Google has accesstype=offline. Salesforce will request refresh tokens a long as you request them. Some applications may want to allow access to data only when the user is logged in.

    Breno will document what Google has done. We can use this as a starting point for a more complete proposal. Also, see Change 2 and Change 3 in http://googleappsdeveloper.blogspot.com/2011/10/upcoming-changes-to-oauth-20-endpoint.html.

  2. Anonymous

    (This post was by Breno, without login.)

    Googles' solution is based on 4 principles:

    1. Handover of credentials to installed and native applications occur in a less trusted context (non-globally routable redirect URLs). So it's preferable to grant offline access to such applications rather than periodically deliver credentials through the same channel. This assumes that native/installed applications are able to store these credentials securely. So for installed applications: - No auto-approval - Offline access by default.

    2. Web applications can receive tokens and codes securely. Granting limited-time access to such applications is preferable in many cases, eliminating the need for them to manage databases of user secrets (refresh_tokens). So for web apps - Auto-approval by default when there is a prior access grant decision by the user - Online access by default

    3. We do not grant permanent access to the account (i.e., issue refresh tokens in exchange for codes) without explicit user consent. So auto-approval of code flows result in a code that can only be redeemed once for an AT.

    4. Auto-approval wins over offline access. So if an application requests both simultaneously, and auto-approval is possible, the auto-approval wins and a code for online access only will be issued. If an app wants a refresh token re-issued to it (unlikely, since the app should have been able to store the refresh_token in the initial authorization), it must indicate that no auto-approval is desired.

    The behavior for web applications is therefore modulated by two parameters, 'access_type' and 'prompt':

    prompt: OPTIONAL. Possible values 'auto' and 'force'. The user will be shown an authorization dialog if either (a) the user has never granted access to the application; or (b) 'prompt=force' is included in the request. The default value is 'auto' if unspecified.
    
    access_type: OPTIONAL. values 'online' and 'offline'. 'access_type=offline' is only legal in code flow and will result in a code that can be redeemed for an RT, as long as the user was prompted for explicit consent during the request (initial authorization or 'prompt=force' was included in the request). If this is an auto-approval context, the value for 'access_type' is ignored.
    

    These allows applications to implement SSO/OpenIDConnect with automatic subsequent auto-approval for either token or code flows. They can write a single button that can be used simultaneously for both 'sign-in to existing account' and 'sign-up for new account'. And they can combine these features with request for offline access, without resulting in powerful and permanent credentials being issued to access the user account with each SSO occurrence:

    - If an application wants to use 'token' flow for SSO/online access they can ignore both parameters.

    - If an application wants to use 'code' flow for SSO/online access they can ignore both parameters.

    - If an application wants to use 'code' flow for SSO but requires offline access they can code their unibutton with 'access_type=offline' without having to discriminate between sign-up and sign-in. They will receive a refresh_token for code exchange in sign-up, but not in sign-in.

    - If the user has revoked the application's access, and then the user tries to connect again, the lack of prior authorization will result in the user seeing an approval page. So RT will be re-provisioned to the app automatically if requested.

    - If the application's database was leaked and the application wants to re-provision all (some) accounts, it could send each refresh_token to the token revocation endpoint. Next time the user comes in, the lack of authorization will result in a prompt and automatically re-provisioning of RT (if requested).

    An application only has to save RTs for given accounts whenever receiving them in exchange for a code, and re-use existing ones otherwise. The 'prompt' parameter is almost never necessary, only when an application wants to 'upgrade' its access level from online to offline.

  3. Nat Sakimura reporter

    Google not comfortable in creating stateless permanent 'password' aka refresh token.

    So, current practice is to issue refresh_token when user is prompted. Never issue refresh token when prompt=none.

    In most web application, refresh token is not needed. Refresh token is required for installed clients. It is never auto-approval.

    George is to record his solution.

    To be continued at IIW.

  4. gffletch

    User Consent

    • User consent is explicitly required but may be "remembered" for future User-RS-AS interactions -- consent is store on a USER:RP basis with the list of permissions (a.k.a. scopes) consented to by the user
    • Remembering user consent is currently an explicit user action (the user must check the check-box)

    Refresh Tokens

    • Refresh tokens are NOT returned for 'token' flow authorization grants
    • Refresh tokens are returned for all code flow authorization grants
    • By default returned access tokens are valid for 1 hr or the life time of the authentication session (which ever is shorter)
    • By default returned refresh tokens are valid for the life of the authentication session
    • If the user logs out of their authentication session, all refresh and access tokens associated with that session are revoked
    • "User not present" use cases can request an 'offline_access' scope in which case the returned refresh_token is NOT bound to the authentication session. Access tokens are still only good for 1 hr.
    • Refresh_tokens returned from a request with the offline_access scope are good for a long time (but not infinite) and may be revoked by the user.
    • User revocation of refresh_tokens covers all tokens granted to a particular application (based on the client_id).
    • "Offline" Refresh tokens may also be revoked via other user actions such as the user changing their password

    I believe there is one benefit to this model that we didn't talk about yesterday. By allowing access_tokens to be refreshed via a refresh_token even when tied to the session, it allows for a back-channel way to refresh the access_token. Using a hidden browser redirect with prompt=none to get back a code to then exchange for the new access_token causes problems when the RP isn't the entity that actually performed the initial federated authentication. For example, when a user logs into MapQuest using a Google account via OpenID Connect, assuming it's AOL's central authentication service that does the OpenID Connect flow with Google, how does MapQuest use a browser redirect to get a new access_token? I believe it has to first redirect to the AOL central authentication service which then has to redirect to Google. If instead, the central authentication service can use the refresh_token to get a new access token, all it takes is a back channel call from MapQuest to the central authentication service to get a new token. This seems much simpler to me.

  5. Nat Sakimura reporter

    So Google and AOL approach does not seem too dissimilar.

    Both requires explicit user consent for obtaining the refresh token.

    Differences:

    1. In AOL's case, refresh token which is bound to the session is returned for 'code' case, while Google does not return it. In AOL's case, the client should send refresh token through the back channel to update the access token, while in Google's case, prompt=none front channel call should be used to get the refreshed access token.
      1. Advantage of AOL's approach is that it allows simpler implementation for the proxied clients (e.g., MapQuest-AOL-Google case).
      2. Google states that their approach allows "unified button" for new registration and authentication. (Is this also achievable with AOL's methodology?)
      3. Perhaps Googles approach allows the server to be stateless while AOL's approach requires it to be stateful?
    2. AOL uses scope to indicate the offline access request, while Google uses a new extension parameter called access_type.
      1. AOL's approach is one less extension variable while Google's approach probably is cleaner than putting everything in the scope bucket.

    I do not think we have consensus on this issue yet. Please discuss.

  6. gffletch

    Updates to Messages draft:

    2.1.2 add a new value for the scope list offline_access OPTIONAL. This scope value requests that access to the user's data / services be granted to the client even when the user is not present (no active authentication session).

    Updates to Standard draft:

    2.3.1 add 'offline_access' to the list of scopes provided in the description of the scope parameter

    Description of offline_access behavior

    If the client has requirements to access the user's data/services when the user is not present (no active authentication session), then the client must request 'offline_access' as one of the scope values and set the prompt parameter to 'consent'. A user MUST always explicitly consent to the return of an access token that contains the 'offline_access' scope. A previously saved user consent is not sufficient to grant the 'offline_access' scope.

    At receipt of a scope parameter containing the 'offline_access' value, the Authorization Server:

    • MUST ensure that the prompt parameter contains 'consent'. If the prompt parameter is does not contain 'consent' then ignore the 'offline_access' request and and return a scope list to the client that does NOT contain the 'offline_access' scope (per the OAuth2 spec)
    • MUST ignore the request for 'offline_access' if the client is using the "Implicit Flow", and return a scope list to the client that does NOT contain the 'offline_access' scope (per the OAuth2 spec).
    • MUST explicitly receive user consent for all clients where the registered 'application_type' is set to 'web' [Discovery section 2.1]
    • SHOULD explicitly receive user consent for all clients where the registered 'application_type' is set to 'native' [Discovery section 2.1]

    Offline access is granted to the client in the form of a refresh_token that enables the client to request new access_tokens even when the user does not have an active authentication session as per the OAuth2 spec. The use of refresh_tokens is not exclusive to the 'offline_access' use case and the Authorization Service MAY grant refresh_tokens in other contexts as well.

    My rationale for this approach:

    1. No need to add "auto" and "force" to the prompt parameter as prompt already has an allowed value of 'consent' which should suffice for the 'force' option. I believe 'auto' should be the default and not explicitly requested.
    2. Add 'offline_access' to the scope list as this is also needed for pure OAuth2 use cases and most authorization servers implementing OpenID Connect will also want to support this use case for OAuth2 as well.
    3. Does not prescribe a strict behavior on when refresh_tokens are issued. This allows the AS to determine if it wants to issue refresh_tokens in the online use case as well as the offline use case.
    4. Explicit user consent is a SHOULD because there are some native client use cases where it's not necessary. For example, a client created by the same company as the AS which the user must download and install into the device. In this case, the user has given "consent" by downloading and installing the application. Requesting explicit user consent in this case is not necessary. The AS is responsible for ensuring that only those clients that meet the security requirements are enabled for this behavior.
  7. Nat Sakimura reporter
    • changed status to open

    Upon reviewing this text, I thought it is too prescriptive. The language should be softened. At the moment, it does not meet enterprise use cases, such as HR department pulling address information to send a pay slip, etc. There are "conditions for processing". As long as it is fulfilling it, it should be fine without explicit consent. Also, one should note that an explicit consent does not always constitute a valid consent.

  8. Log in to comment