Subject: [OAUTH-WG] Implementation questions around refresh token rotation

From: Aaron Parecki <[email-masked]>
Date: Tue, 6 Oct 2020 15:05:30 -0700

Hi all, I have a couple questions for those of you who have implemented
refresh token rotation...

Have you included the option of a grace period on refresh token use,
allowing multiple uses within some time window? I'm wondering because a
grace period where a refresh token may be used more than once would work
around the problem that has been brought up, of a mobile app accidentally
using a refresh token more than once during normal operation because
different threads are unable to coordinate between themselves. However that
also kind of defeats the purpose since attacks within that grace period
would be hard to detect. I'm looking for an idea of where people have
landed on that issue in practice.

If you have implemented a grace period, then how do you handle expiring the
additional refresh tokens that have been granted? For example, if RT "R1"
is used twice, resulting in new ATs "A1.1", "A1.2" and new RTs "R1.1" and
"R1.2", what happens if "R1.2" is then later used? Would you invalidate
"R1.1" at that point? If so, why, and if not, why not?

It would be most interesting to hear practical experience from people who
have already built refresh token rotation into a system.

Thanks!

---
Aaron Parecki
https://aaronparecki.com

---

From: <[email-masked]>
Date: Tue, 6 Oct 2020 15:28:25 -0700

Hey Aaron,

Auth0 does offer a configurable grace period, during which the “preceding” token can be reused. 

I am not 100% sure what we do in the exact scenario you described, and I will double check for you, but here’s my intuition.

The operation redeem(RT_n) should result in AT, RT_n+1. The grace period just extends the time in which the operation can occur, but every operation should be idempotent. All repeats of that operation within the grace period should have the same result, which means that every resulting RT is a representative of the RT_n+1 class, hence all valid at the same time. After the grace period elapses, RT_n is invalid, and that’s it.

So, in your example I would consider RT1.1 and RT1.2 as equivalent, as they are both representatives of the RT_n+1 equivalence class.

It would be very hard to do otherwise, given that network operations aren’t guaranteed to be concluded in the order they were executed without semaphores, and above all the network failures the grace period is designed to handle can apply to any of the requests, regardless of the order.

From: OAuth <[email-masked]> On Behalf Of Aaron Parecki
Sent: Tuesday, October 6, 2020 3:06 PM
To: OAuth WG <[email-masked]>
Subject: [OAUTH-WG] Implementation questions around refresh token rotation

Hi all, I have a couple questions for those of you who have implemented refresh token rotation...

Have you included the option of a grace period on refresh token use, allowing multiple uses within some time window? I'm wondering because a grace period where a refresh token may be used more than once would work around the problem that has been brought up, of a mobile app accidentally using a refresh token more than once during normal operation because different threads are unable to coordinate between themselves. However that also kind of defeats the purpose since attacks within that grace period would be hard to detect. I'm looking for an idea of where people have landed on that issue in practice.

If you have implemented a grace period, then how do you handle expiring the additional refresh tokens that have been granted? For example, if RT "R1" is used twice, resulting in new ATs "A1.1", "A1.2" and new RTs "R1.1" and "R1.2", what happens if "R1.2" is then later used? Would you invalidate "R1.1" at that point? If so, why, and if not, why not?

It would be most interesting to hear practical experience from people who have already built refresh token rotation into a system.

Thanks!

---

Aaron Parecki

https://aaronparecki.com

---

From: Jeff Craig <[email-masked]>
Date: Tue, 6 Oct 2020 17:56:43 -0500

My experience is more from the Client side of the equation on this problem,
but I do have some thoughts. Our goal is to prevent cases where we lose the
ability to Refresh a Token due to transient issues (which have run the
gamut from network problems to bad software updates on the AS side). Our
use case also does all token handling server-side, so our threat model is
not the same as the mobile application you described. There is a clear
tradeoff in reducing user friction with additional authorization events,
and securing access.

The recommendation my team typically gives people building Authorization
Servers with Refresh Token Rotation is to keep the old refresh token until
they see the new one (which means that there are generally two refresh
tokens valid at any point in time, an unfortunate trade-off). A more
difficult, but potentially plausible implementation would be to hold onto
the older Refresh Token until the newly issued Access Token is used (thus
implying the refresh was successful on both sides).

We aren't trying to protect against multiple in-flight refreshes though
(we've done a LOT of work to attempt to remove that possibility in a
globally consistent manner), we're trying to protect against a network
interruption that prevents the first use of R1, so our assumption is that
R2.1 was completely lost, and only R2.2 matters moving forward. Meaning: R1
is sent, A/R2.1 is dropped in flight, R1 is sent again, A/R2.2 is returned
and stored. Since R1 was seen a second time, we recommend that R2.1 be
ignored in future. Next refresh will use R2.2, at which point R1 should
never be seen again.

The biggest issue that I see with a time-based grace period is that for
many offline tasks, a single refresh failure may be ignored by the client,
and it could be hours before the second refresh attempt using the older
refresh token is made (depending on time of day and what these requests are
being used for), making the grace period low value in that case.

On Tue, Oct 6, 2020 at 5:28 PM <vittorio.bertocci=[email-masked]>
wrote:

> I am not 100% sure what we do in the exact scenario you described, and I
> will double check for you, but here’s my intuition.
>
>
>
> The operation redeem(RT_n) should result in AT, RT_n+1. The grace period
> just extends the time in which the operation can occur, but every operation
> should be idempotent. All repeats of that operation within the grace period
> should have the same result, which means that every resulting RT is a
> representative of the RT_n+1 class, hence all valid at the same time. After
> the grace period elapses, RT_n is invalid, and that’s it.
>
> So, in your example I would consider RT1.1 and RT1.2 as equivalent, as
> they are both representatives of the RT_n+1 equivalence class.
>
>
>
> It would be very hard to do otherwise, given that network operations
> aren’t guaranteed to be concluded in the order they were executed without
> semaphores, and above all the network failures the grace period is designed
> to handle can apply to any of the requests, regardless of the order.
>
>
>
> *From:* OAuth <[email-masked]> *On Behalf Of *Aaron Parecki
> *Sent:* Tuesday, October 6, 2020 3:06 PM
> *To:* OAuth WG <[email-masked]>
> *Subject:* [OAUTH-WG] Implementation questions around refresh token
> rotation
>
>
>
> If you have implemented a grace period, then how do you handle expiring
> the additional refresh tokens that have been granted? For example, if RT
> "R1" is used twice, resulting in new ATs "A1.1", "A1.2" and new RTs "R1.1"
> and "R1.2", what happens if "R1.2" is then later used? Would you invalidate
> _______________________________________________
> OAuth mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/oauth
>

---

From: Neil Madden <[email-masked]>
Date: Wed, 7 Oct 2020 08:20:41 +0100

> On 6 Oct 2020, at 23:05, Aaron Parecki <[email-masked]> wrote:
> 
> 

Right. We’ve avoided adding a grace period for this reason. An attacker in a position to steal a refresh token is also presumably in a position to see when the legitimate client uses it and then sneak in just afterwards within the grace period. You could maybe only allow grace period refreshes from the same IP address but I’m not sure that would always hold in the flaky mobile network scenarios (eg refresh fails on 2G due to disconnect then client switches to Wifi hotspot and retries).

---

From: Torsten Lodderstedt <[email-masked]>
Date: Sat, 10 Oct 2020 12:10:13 +0200

> Am 07.10.2020 um 09:20 schrieb Neil Madden <[email-masked]>:
> 
> 
> 

We did not implement a grace period for the same reason. Refresh token rotation is a countermeasure against refresh token theft and replay for public client. A grace period to some degree limits it effectiveness against exactly this attack.

best regards,
Torsten.

---

From: David Waite <[email-masked]>
Date: Sat, 10 Oct 2020 14:41:54 -0600

On Oct 6, 2020, at 16:05, Aaron Parecki <[email-masked]> wrote:
> However that also kind of defeats the purpose since attacks within that grace period would be hard to detect. I'm looking for an idea of where people have landed on that issue in practice.

This is effectively a race condition, and a grace period hides your ability to detect the race. Because of the race condition is no guarantee that the second refresh token is the one that is retained, the client could still fail once it needs its next access token.

Instead, an ideal system would allow you to make a security exception and turn off rotation, possibly only until the client revises their logic.

-DW

---

From: Sascha Preibisch <[email-masked]>
Date: Sat, 10 Oct 2020 14:16:23 -0700

In the past, customers brought to our attention that some clients were not
able to receive a new refresh_token and use it right away. For that use
case we added a different type of rotation. The new refresh_token was
exactly the same as the given one. Except that it had a new expiration
date, lifetime and such. It was usually tight to exactly one scope valid
scope value.
Since customers were able to configure this behaviour for specific clients,
they used this feature for single or a limited number of use cases.
Other than that, a used refresh_token became invalid once it was used with
no overlap.

Regards,
Sascha

On Sat, 10 Oct 2020 at 13:42, David Waite <david=
[email-masked]> wrote:

> > However that also kind of defeats the purpose since attacks within that
> grace period would be hard to detect. I'm looking for an idea of where
> people have landed on that issue in practice.
>
> This is effectively a race condition, and a grace period hides your
> ability to detect the race. Because of the race condition is no guarantee
> that the second refresh token is the one that is retained, the client could
> still fail once it needs its next access token.
>
> Instead, an ideal system would allow you to make a security exception and
> turn off rotation, possibly only until the client revises their logic.
>
> -DW

---

From: Dave Tonge <[email-masked]>
Date: Mon, 12 Oct 2020 06:43:30 +0200

> Our goal is to prevent cases where we lose the ability to Refresh a Token
due to transient issues (which have run the gamut from network problems to
bad software updates on the AS side).

We've seen this issue quite a bit and it's very frustrating. I would
suggest that refresh token rotation is not used for confidential clients
that authenticate with private_key_jwt or tls_client_auth.

On Wed, 7 Oct 2020 at 00:57, Jeff Craig <jeffcraig=
[email-masked]> wrote:

> My experience is more from the Client side of the equation on this
> problem, but I do have some thoughts. Our goal is to prevent cases where we
> lose the ability to Refresh a Token due to transient issues (which have run
> the gamut from network problems to bad software updates on the AS side).
> Our use case also does all token handling server-side, so our threat model
> is not the same as the mobile application you described. There is a clear
> On Tue, Oct 6, 2020 at 5:28 PM <vittorio.bertocci=
> [email-masked]> wrote:
>
>> Hey Aaron,
>>

-- 
Dave Tonge

-- 

Moneyhub Enterprise is a trading style of Moneyhub Financial Technology 
Limited which is authorised and regulated by the Financial Conduct 
Authority ("FCA"). Moneyhub Financial Technology is entered on the 
Financial Services Register (FRN 809360) at https://register.fca.org.uk/ 
<https://register.fca.org.uk/>. Moneyhub Financial Technology is registered 
in England & Wales, company registration number 06909772. Moneyhub 
Financial Technology Limited 2020 © Moneyhub Enterprise, Regus Building, 
Temple Quay, 1 Friary, Bristol, BS1 6EA. 

DISCLAIMER: This email 
(including any attachments) is subject to copyright, and the information in 
it is confidential. Use of this email or of any information in it other 
than by the addressee is unauthorised and unlawful. Whilst reasonable 
efforts are made to ensure that any attachments are virus-free, it is the 
recipient's sole responsibility to scan all attachments for viruses. All 
calls and emails to and from this company may be monitored and recorded for 
legitimate purposes relating to this company's business. Any opinions 
expressed in this email (or in any attachments) are those of the author and 
do not necessarily represent the opinions of Moneyhub Financial Technology 
Limited or of any other group company.

---

From: Neil Madden <[email-masked]>
Date: Mon, 12 Oct 2020 07:57:47 +0100

I’m not sure I agree with this advice. Singling out private_key_jwt and tls_client_auth suggests that the problem is an attacker being able to eavesdrop on the refresh request itself and then replay it. But if they are able to do that then they can instead just steal the access tokens from the response.

I think refresh token rotation is better thought of as providing protection against insecure token storage on the client (e.g. in browser localStorage). Both public and confidential clients are capable of creating secure connections with TLS, but we assume that confidential clients (regardless of auth mechanism) have access to secure storage - otherwise they shouldn’t be confidential clients in the first place.

I think the same reasoning applies here too - if a client has insecure storage then an attacker could just steal the access tokens instead. But I think the difference is that an attacker is more likely to gain temporary access to local storage (e.g. when the user goes to the bathroom and leaves their device unlocked) than they are to gain temporary access to eavesdrop on a connection. The kind of vulnerabilities that allow eavesdropping tend to be repeatable so the attacker doesn’t need to steal a refresh token to ensure ongoing access, they can just steal the access tokens every time the client refreshes.

That said, there are lots of vulnerabilities that would give an attacker repeatable access to the client’s local storage - e.g. XSS - so refresh token rotation only catches a subset of possible attacks.

— Neil

> On 12 Oct 2020, at 05:43, Dave Tonge <[email-masked]> wrote:
> 
> > Our goal is to prevent cases where we lose the ability to Refresh a Token due to transient issues (which have run the gamut from network problems to bad software updates on the AS side).
> 
> We've seen this issue quite a bit and it's very frustrating. I would suggest that refresh token rotation is not used for confidential clients that authenticate with private_key_jwt or tls_client_auth. 
> 
> On Wed, 7 Oct 2020 at 00:57, Jeff Craig <jeffcraig=[email-masked] <mailto:[email-masked]>> wrote:
> My experience is more from the Client side of the equation on this problem, but I do have some thoughts. Our goal is to prevent cases where we lose the ability to Refresh a Token due to transient issues (which have run the gamut from network problems to bad software updates on the AS side). Our use case also does all token handling server-side, so our threat model is not the same as the mobile application you described. There is a clear tradeoff in reducing user friction with additional authorization events, and securing access.
> 
> The recommendation my team typically gives people building Authorization Servers with Refresh Token Rotation is to keep the old refresh token until they see the new one (which means that there are generally two refresh tokens valid at any point in time, an unfortunate trade-off). A more difficult, but potentially plausible implementation would be to hold onto the older Refresh Token until the newly issued Access Token is used (thus implying the refresh was successful on both sides).
> 
> We aren't trying to protect against multiple in-flight refreshes though (we've done a LOT of work to attempt to remove that possibility in a globally consistent manner), we're trying to protect against a network interruption that prevents the first use of R1, so our assumption is that R2.1 was completely lost, and only R2.2 matters moving forward. Meaning: R1 is sent, A/R2.1 is dropped in flight, R1 is sent again, A/R2.2 is returned and stored. Since R1 was seen a second time, we recommend that R2.1 be ignored in future. Next refresh will use R2.2, at which point R1 should never be seen again.
> 
> The biggest issue that I see with a time-based grace period is that for many offline tasks, a single refresh failure may be ignored by the client, and it could be hours before the second refresh attempt using the older refresh token is made (depending on time of day and what these requests are being used for), making the grace period low value in that case.
> 
> On Tue, Oct 6, 2020 at 5:28 PM <vittorio.bertocci=[email-masked] <mailto:[email-masked]>> wrote:
> Hey Aaron,
> 
> From: OAuth <[email-masked] <mailto:[email-masked]>> On Behalf Of Aaron Parecki
> To: OAuth WG <[email-masked] <mailto:[email-masked]>>
> https://aaronparecki.com <https://aaronparecki.com/>
>  
> 
> [email-masked] <mailto:[email-masked]>
> https://www.ietf.org/mailman/listinfo/oauth <https://www.ietf.org/mailman/listinfo/oauth>
> [email-masked] <mailto:[email-masked]>
> https://www.ietf.org/mailman/listinfo/oauth <https://www.ietf.org/mailman/listinfo/oauth>
> 
> 
> -- 
> Dave Tonge
> 
> 
> Moneyhub Enterprise is a trading style of Moneyhub Financial Technology Limited which is authorised and regulated by the Financial Conduct Authority ("FCA"). Moneyhub Financial Technology is entered on the Financial Services Register (FRN 809360) at https://register.fca.org.uk/ <https://register.fca.org.uk/>. Moneyhub Financial Technology is registered in England & Wales, company registration number 06909772. Moneyhub Financial Technology Limited 2020 © Moneyhub Enterprise, Regus Building, Temple Quay, 1 Friary, Bristol, BS1 6EA. 
> 
> DISCLAIMER: This email (including any attachments) is subject to copyright, and the information in it is confidential. Use of this email or of any information in it other than by the addressee is unauthorised and unlawful. Whilst reasonable efforts are made to ensure that any attachments are virus-free, it is the recipient's sole responsibility to scan all attachments for viruses. All calls and emails to and from this company may be monitored and recorded for legitimate purposes relating to this company's business. Any opinions expressed in this email (or in any attachments) are those of the author and do not necessarily represent the opinions of Moneyhub Financial Technology Limited or of any other group company.
> 
>

---

From: Dave Tonge <[email-masked]>
Date: Mon, 12 Oct 2020 09:03:45 +0200

Hi Neil

 > refresh token rotation is better thought of as providing protection
against insecure token storage on the client

I agree with your reasoning - and that was more the intent of what I said.
We've seen refresh token rotation used for confidential clients that have
secure storage (i.e. are run in a data center not on a mobile device) and
it has caused problems with zero additional security benefits.

Dave

On Mon, 12 Oct 2020 at 08:57, Neil Madden <[email-masked]> wrote:

> I’m not sure I agree with this advice. Singling out private_key_jwt and
> tls_client_auth suggests that the problem is an attacker being able to
> eavesdrop on the refresh request itself and then replay it. But if they are
> able to do that then they can instead just steal the access tokens from the
> response.
>
> I think refresh token rotation is better thought of as providing
> protection against insecure token storage on the client (e.g. in browser
> localStorage). Both public and confidential clients are capable of creating
> secure connections with TLS, but we assume that confidential clients
> (regardless of auth mechanism) have access to secure storage - otherwise
> they shouldn’t be confidential clients in the first place.
>
> I think the same reasoning applies here too - if a client has insecure
> storage then an attacker could just steal the access tokens instead. But I
> think the difference is that an attacker is more likely to gain temporary
> access to local storage (e.g. when the user goes to the bathroom and leaves
> their device unlocked) than they are to gain temporary access to eavesdrop
> on a connection. The kind of vulnerabilities that allow eavesdropping tend
> to be repeatable so the attacker doesn’t need to steal a refresh token to
> ensure ongoing access, they can just steal the access tokens every time the
> client refreshes.
>
> That said, there are lots of vulnerabilities that would give an attacker
> repeatable access to the client’s local storage - e.g. XSS - so refresh
> token rotation only catches a subset of possible attacks.
>
> — Neil
>
> > Our goal is to prevent cases where we lose the ability to Refresh a
> Token due to transient issues (which have run the gamut from network
> problems to bad software updates on the AS side).
>
>>> It would be most interesting to hear practical experience from people
>>> who have already built refresh token rotation into a system.
>>>
>>>
>>>
>>> Thanks!
>>>
>>>
>>> ---
>>>
>>> Aaron Parecki
>>>
>>> https://aaronparecki.com
>>>
>>>
> Financial Services Register (FRN 809360) at https://register.fca.org.uk/.
> Moneyhub Financial Technology is registered in England & Wales, company
> registration number 06909772. Moneyhub Financial Technology Limited 2020 ©
> Moneyhub Enterprise, Regus Building, Temple Quay, 1 Friary, Bristol, BS1
> 6EA.
>
> DISCLAIMER: This email (including any attachments) is subject to
> copyright, and the information in it is confidential. Use of this email or
> of any information in it other than by the addressee is unauthorised and
> unlawful. Whilst reasonable efforts are made to ensure that any attachments
> are virus-free, it is the recipient's sole responsibility to scan all
> attachments for viruses. All calls and emails to and from this company may
> be monitored and recorded for legitimate purposes relating to this
> company's business. Any opinions expressed in this email (or in any
> attachments) are those of the author and do not necessarily represent the
> opinions of Moneyhub Financial Technology Limited or of any other group
> company.
>

-- 

DISCLAIMER: This email

---

From: Torsten Lodderstedt <[email-masked]>
Date: Mon, 12 Oct 2020 11:15:15 +0200

> Am 12.10.2020 um 09:04 schrieb Dave Tonge <[email-masked]>:
> 
> 
> Hi Neil
> 
>  > refresh token rotation is better thought of as providing protection against insecure token storage on the client
> 
> I agree with your reasoning - and that was more the intent of what I said. We've seen refresh token rotation used for confidential clients that have secure storage (i.e. are run in a data center not on a mobile device) and it has caused problems with zero additional security benefits. 

Those are good examples of why refresh token rotation should not be used if there are better ways available to protect refresh tokens from replay. Client authentication or sender constrained refresh tokens are the better choice.

>>>> On Wed, 7 Oct 2020 at 00:57, Jeff Craig <jeffcraig=[email-masked]> wrote:
>>>>> On Tue, Oct 6, 2020 at 5:28 PM <vittorio.bertocci=[email-masked]> wrote:
>>>>> Hey Aaron,
>>>>> 
>>> Moneyhub Enterprise is a trading style of Moneyhub Financial Technology Limited which is authorised and regulated by the Financial Conduct Authority ("FCA"). Moneyhub Financial Technology is entered on the Financial Services Register (FRN 809360) at https://register.fca.org.uk/. Moneyhub Financial Technology is registered in England & Wales, company registration number 06909772. Moneyhub Financial Technology Limited 2020 © Moneyhub Enterprise, Regus Building, Temple Quay, 1 Friary, Bristol, BS1 6EA. 
>>> 
> Moneyhub Enterprise is a trading style of Moneyhub Financial Technology Limited which is authorised and regulated by the Financial Conduct Authority ("FCA"). Moneyhub Financial Technology is entered on the Financial Services Register (FRN 809360) at https://register.fca.org.uk/. Moneyhub Financial Technology is registered in England & Wales, company registration number 06909772. Moneyhub Financial Technology Limited 2020 © Moneyhub Enterprise, Regus Building, Temple Quay, 1 Friary, Bristol, BS1 6EA. 
>

---

From: David Waite <[email-masked]>
Date: Mon, 12 Oct 2020 03:54:26 -0600

An AS may decide refresh token rotation is useful for other reasons (such as if the token is an encrypted value and the AS cluster does key rotation), or may decide to rotate all tokens for consistency.

Eventually best practices may indicate sender constrained tokens for public clients. At that point, refresh rotation may not be security practice but could still be something an AS does as part of its own design. And an AS may elect to do this often so that clients fail (and correct their logic) faster.

-DW

> On Oct 12, 2020, at 03:15, Torsten Lodderstedt <torsten=[email-masked]> wrote:
> 
>> 
>> Am 12.10.2020 um 09:04 schrieb Dave Tonge <[email-masked] <mailto:[email-masked]>>:
>> 
>> 
>> Hi Neil
>>

---

From: Torsten Lodderstedt <[email-masked]>
Date: Mon, 12 Oct 2020 14:23:13 +0200

Out of curiosity: Have you seen this in practice? I’m asking since most/all refresh token implementations I have seen are handles. Just rotating for consistency makes especially the live of server based clients harder as they need to propagate such a change through the cluster.

> Am 12.10.2020 um 11:54 schrieb David Waite <david=[email-masked]>:
>