[OAUTH-WG] Re: Refresh Token Rotation

David Waite <david@alkaline-solutions.com> Mon, 05 August 2024 22:54 UTC

Return-Path: <david@alkaline-solutions.com>
X-Original-To: oauth@ietfa.amsl.com
Delivered-To: oauth@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 213FCC14F702 for <oauth@ietfa.amsl.com>; Mon, 5 Aug 2024 15:54:47 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.905
X-Spam-Level:
X-Spam-Status: No, score=-1.905 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, HTML_MESSAGE=0.001, RCVD_IN_ZEN_BLOCKED_OPENDNS=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, URIBL_BLOCKED=0.001, URIBL_DBL_BLOCKED_OPENDNS=0.001, URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=ham autolearn_force=no
Received: from mail.ietf.org ([50.223.129.194]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FCFtcrTYw1AL for <oauth@ietfa.amsl.com>; Mon, 5 Aug 2024 15:54:43 -0700 (PDT)
Received: from caesium6.alkaline.solutions (caesium6.alkaline.solutions [157.230.133.164]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 3D77DC15154E for <oauth@ietf.org>; Mon, 5 Aug 2024 15:54:43 -0700 (PDT)
From: David Waite <david@alkaline-solutions.com>
Authentication-Results: caesium6.alkaline.solutions; auth=pass smtp.mailfrom=david@alkaline-solutions.com
Message-Id: <FD4B58DA-88A2-4CC8-9560-23C6C3FE4FDB@alkaline-solutions.com>
Content-Type: multipart/alternative; boundary="Apple-Mail=_1648E351-E6FD-4217-BB52-1A30FB22FC09"
Mime-Version: 1.0
Date: Mon, 05 Aug 2024 16:54:30 -0600
In-Reply-To: <CADU05gMuKgptBKVqQQoJY-HiYizbCAdy+eV3eYo8QAUmtzn7Mg@mail.gmail.com>
To: Indeewari Wijesiri <indeewarii@gmail.com>
References: <CADU05gP9Zn_18bsmmiUgLNVsDGN9HEurJvF30jCbT5-nx4ycMg@mail.gmail.com> <CAJot-L2qJBRfgc2CpnokjP2Dk8iwJ9L7UDBuj+j6a+D6JG99oQ@mail.gmail.com> <CADU05gMuKgptBKVqQQoJY-HiYizbCAdy+eV3eYo8QAUmtzn7Mg@mail.gmail.com>
X-Spamd-Bar: --
Message-ID-Hash: ZLLWJOKIOKKNDUKK75TSVGUPRY26KEQE
X-Message-ID-Hash: ZLLWJOKIOKKNDUKK75TSVGUPRY26KEQE
X-MailFrom: david@alkaline-solutions.com
X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-oauth.ietf.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header
CC: oauth@ietf.org
X-Mailman-Version: 3.3.9rc4
Precedence: list
Subject: [OAUTH-WG] Re: Refresh Token Rotation
List-Id: OAUTH WG <oauth.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/IDlOztlajx25aMPIy_hSEfd9QpA>
List-Archive: <https://mailarchive.ietf.org/arch/browse/oauth>
List-Help: <mailto:oauth-request@ietf.org?subject=help>
List-Owner: <mailto:oauth-owner@ietf.org>
List-Post: <mailto:oauth@ietf.org>
List-Subscribe: <mailto:oauth-join@ietf.org>
List-Unsubscribe: <mailto:oauth-leave@ietf.org>

On Aug 2, 2024, at 5:36 AM, Indeewari Wijesiri <indeewarii@gmail.com> wrote:

> Hi Warren,
> 
> Thank you for your attention.
> 
> When public web clients use the authorization code grant for authentication, a successful response includes an access token and, optionally, a refresh token. If the access token is a JWT rather than an opaque token, the identity server will issue a new JWT access token for each authentication request with the same client_id and scope, based on the "issued at" (iat) claim. This means each authentication attempt generates a new JWT access token.
> 


Each interaction with the authorization endpoint with the user MUST generate a new authorization code when using code grant type. An authorization code MUST be short lived and single-use.

Beyond that, it is expected that servers have their own policy. There’s no requirement they do refresh token rotation or support refreshes at all. There is AFAIK no requirement that the new access token be different than a previous access token, on grant or refresh. These are all policies for the AS to implement.

Refresh token rotation (and making sure you issue new access tokens on refresh) is effectively using the refresh token mechanism as a way to detect cloning. If someone exfiltrates the access token (or even the access and refresh token) and uses them independently, eventually the two clients will be out of sync, and the server will have visibility that there are potentially multiple “clients” using the tokens.

The queued security topics BCP ( https://datatracker.ietf.org/doc/draft-ietf-oauth-security-topics/ ) and the BCPs for native applications and in-progress one for browser-based applications are likely the best resources here for policy recommendations for AS implementations/deployments. There are some cross-cutting recommendations for all clients, but there may not be a best-fit policy if you have client diversity (say, browser-based applications, smart tv and set-top box applications, and third party hosted services needing long-running data access)

Another way of looking at it is that a client is being authorized for delegated access for a period of time; you can represent that as a single access token, a series of access tokens created off of a single refresh token, or a series of access and refresh tokens. These could all effectively give the same access over the same period of time.

Business and security/risk policies at the AS make this decision opaquely; different clients might get tokens with different behaviors, and tokens with different behaviors may be created by the scope or resource being requested. The BCPs provide guidance to help the AS understand appropriate security and risk decisions.
> In this context, how should the refresh token behave? Is it advisable to use a long-lived refresh token in conjunction with the JWT access token, or should the refresh token be rotated each time a new JWT access token is issued?
> 

The browser-apps BCP (as an example) indicates that if you do, they MUST either rotate on each refresh or that the refresh tokens be sender-constrained (through a mechanism like DPoP). It requires certain token lifetime policies be in place, but does not give mandates on what these lifetimes should be (e.g. 4 hours or 4 years). This advice comes from the higher risk of token exfiltration in the browser environment when the credential is held within local storage which is easily readable by javascript or the user.

I don’t expect it is common policy for a new access token (issued outside a refresh, e.g. code grant) is associated with an existing authorization grant. 

A browser-based client or native app client can have multiple concurrent authorizations, because the end user may have multiple browsers/devices. These sorts of “client instances” usually don’t have a way to be individually identified, so (from the AS perspective) they have a lifetime of the token validity. If a client does a code grant, there’s no way (in the core protocol) to identify as a that being related to a previous grant.
> For opaque access tokens, since they are not renewed with each request, a long-lived refresh token can be used.
> 
I am making an assumption that by ‘opaque access tokens’, you are speaking to requiring a resource server to use an interface like the token introspection endpoint to determine validity and purpose, rather than introspecting the token contents based on some known format like RFC9068. 

All access tokens should be effectively opaque to clients, so whether a token is opaque or parsable doesn’t affect malicious clients having authorization. Access token interpretation is set between resource servers and the AS.

-DW