Hero Banner

Multi-Factor Authentication (MFA)

Learn and ask questions on how to implement MFA

Reply
ionos_uk
Visitor 1

OAuth Refresh token has expired after 90 days

We have encountered an issue on our live environment:

The Multi Factor Authentication does not work anymore.

 

We try to authenticate using an OAuth Refresh Token (this authentication mechanism has been recommended by the Yammer group "Partner Center Security Guidance", which now has been closed).

But since today, this authentication does not work anymore, but we get the following error message:
invalid_grant: AADSTS700082: The refresh token has expired due to inactivity. The token was issued on 2019-01-02T09:19:53.5422744Z and was inactive for 90.00:00:00.:

 

But I am absolutely sure that this refresh token has been successfully used yesterday.

 

The Microsoft documentation https://docs.microsoft.com/en-us/graph/auth-overview says that an OAuth Refresh token should only expired if it has been inactive for 90 days. But our tokens were used. Therefore the tokens should not expire!

 

Why do we now have a live incident? What went wrong?

 

Please not that we are selling in 12 different markets, and therefore have 12 different partner accounts, and therefore 24 different OAuth refresh tokens (one for the live environment and one for the sandbox). Therefore it is not this easy to update the 24 OAuth refresh tokens.

 

What can we do to avoid similar production incidents in the future?

 

We are regularily using the refresh tokens to get new access tokens. We do this using the call "POST /{tenant}/oauth2/token grant_type=refresh_token&refresh_token=..." (see https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code). The response of this call not only contains the access token, but also a new refresh token. At the moment, we ignore the new refresh token that is returned. Should we store and use the new refresh token that is returned by this call, or would the new refresh token also expire at the same time?

 

Does Microsoft offer a way to find out the expiry time or the issued-at-date of a refresh token?

17 REPLIES 17
1682
Visitor 1

AADSTS70008: The provided authorization code or refresh token has expired due to inactivity. Send a new interactive authorization request for this user and resource. Trace ID: cadfb933-6c27-40ec-8268-2e96e45d1700 Correlation ID: 3797be50-e5a1-41ba-bd43-af0cb712b8e9 Timestamp: 2021-03-10 13:10:08Z

sergesettels
Level 2 Contributor

Please review my reply in this thread. Please check that you store your token(cache) also after AquireTokenSilent. You will get a new refresh token which you schould use in sequential requests. In my case I did not (correctly) store it, so I used the refresh token which I aquired the first time when I used AquireTokenInteractive. That token will expire after 90 days.

 

My full reply was:

I have found the problem in my situation.

 

There are two authentication flows: a confidentialclient which authenticates the application. The application has access to the resources of your organisation, but you have little control over who uses the software. This is, even for background processes, not workable when you develop your own software for multiple customers (you cannot guarantee that customer 1 might never access data from customer 2).

In that case you develop a Public Client where you get access via a user's account via AquireTokenInteractive (that method also supports multifactor authentication and it shows any consentscreen necessary). Once you have access you can use AquireTokenSilent to renew the token. Note that AcquireTokenSilent DOES return a refresh token (valid for 90 days), and you should make sure you store this after every request. The refreshtoken is not visible if you look in the debugger, but it is visible if you use Fiddler to view the raw data (and decode the token).

 

That was in hindside my problem: I created a daemon process for which the interactive flow does not seem logical, and since I had token issues I went for the confidential flow. But there you do not get the consent screens and it does not work with multifactor authentication.

 

My conclusion: if you are developing 3rd party software then even for background (daemon) processes you could (should) use the publicclient flow. There is no problem with the token process: it will continue to work forever once you aquire a token. Only when your software is 'down' for more than 90 days you will need to log in again (and when access for your app is changed from the client's azure account)

 

Relevant links:
https://docs.microsoft.com/nl-nl/azure/active-directory/develop/msal-client-applications

https://docs.microsoft.com/nl-nl/azure/active-directory/develop/msal-net-acquire-token-silently

elgoldman
Visitor 1

AADSTS700082: The refresh token has expired due to inactivity.  - Was my error in Teams.  Just a follow up:

 

I was trying to load a Teams list from a spreadsheet and received this error.  Just a note, it had nothing to do with OAuth and I am not sure why this was the error.  In playing with various approaches, I watched a video on setting up lists in Sharepoint.  They identified a step I did not do on the spreadsheet that was necessary for Sharepoint.  It had to do with setting the spreadsheet up into a "Table" (Select range, insert --> Table) and saved it.  Once I did that, I did not get the OAuth error (so it might just be the call to an error, in error).  Just for anyone searching for help as Microsoft had no idea what it was either.  

sergesettels
Level 2 Contributor

When you access a mailbox of a specific user via a background service using MS Graph, the token will expire after 90 days since Graph does not return a refresh token (learned from experience).

Using administrator consent should resolve this issue, but the only choice is to get access to ALL mailboxes of the organization. This is way to great a security risk for this task.

 

Does anybody know a middle ground for this?
Is there a way to get the refresh token when using user consent, or limit admin consent to 1 mailbox?

sergesettels
Level 2 Contributor

Note that I use AcquireTokenSilent from the Microsoft.Identity.Client library.

sergesettels
Level 2 Contributor

I have found the problem in my situation.

 

There are two authentication flows: a confidentialclient which authenticates the application. The application has access to the resources of your organisation, but you have little control over who uses the software. This is, even for background processes, not workable when you develop your own software for multiple customers (you cannot guarantee that customer 1 might never access data from customer 2).

In that case you develop a Public Client where you get access via a user's account via AquireTokenInteractive (that method also supports multifactor authentication and it shows any consentscreen necessary). Once you have access you can use AquireTokenSilent to renew the token. Note that AcquireTokenSilent DOES return a refresh token (valid for 90 days), and you should make sure you store this after every request. The refreshtoken is not visible if you look in the debugger, but it is visible if you use Fiddler to view the raw data (and decode the token).

 

That was in hindside my problem: I created a daemon process for which the interactive flow does not seem logical, and since I had token issues I went for the confidential flow. But there you do not get the consent screens and it does not work with multifactor authentication.

 

My conclusion: if you are developing 3rd party software then even for background (daemon) processes you could (should) use the publicclient flow. There is no problem with the token process: it will continue to work forever once you aquire a token. Only when your software is 'down' for more than 90 days you will need to log in again (and when access for your app is changed from the client's azure account)

 

Relevant links:
https://docs.microsoft.com/nl-nl/azure/active-directory/develop/msal-client-applications

https://docs.microsoft.com/nl-nl/azure/active-directory/develop/msal-net-acquire-token-silently

cblackuk
Level 2 Contributor

@idwilliamsThanks for the clarification.

 

It is a bit sad that we cannot really do much about it currently but if we could get them to publish new policy to allow us to increase or remove the expiration - that would be lovely.

 

I know you said that you will update us here but can you also send and update on the Yammer group? 🙂

 

Thanks for looking into it as well mate... really appreciate the help!

 

 

horizondave
Visitor 1

FYI I have found another cause of this error.

The AdalTokenCache.cs file generated by the MVC5 template seems to have had a bug in the past, which has now been fixed.

The bug is in the AfterAccessNotification method where an "if Cache == null" check is missing.

It may be down to whether you choose single tenant / multi tenant when creating your initial project, but either way I've just googled "adaltokencache.cs" and got examples of each:

 

1. This one contains the bug.

https://github.com/OfficeDev/O365-WebApp-SingleTenant/blob/master/O365-WebApp-SingleTenant/Models/ADALTokenCache.cs

 

2. This one works correctly.

https://github.com/OfficeDev/O365-ASPNETMVC-Start/blob/master/O365-APIs-Start-ASPNET-MVC/Models/ADALTokenCache.cs

 

The bug causes multiple copies of a user's accesstoken/refreshtoken to be stored in the database - but because of the "FirstOrDefault" on retrieval, only the earliest one stored is ever retrieved - meaning after 90 days the refresh token expires and breaks the user access to the application.

 

cblackuk
Level 2 Contributor

@idwilliams  Thanks for getting back to us and for clarification.

 

In this case the documentation is wrong and should be updated... Also, are there any plans to allow us to extend this 90 days period via custom policy?

 

Currently based on somebody else's recommendation I automated the "refresh" of refresh token but I still think it is a silly thing to do and we should be allowed to keep it until revoked when it is constantly being used...

idwilliams
Moderator

@cblackuk this is something that will need to be explored with the Azure AD team. I know they are currently planning a replacement for the policies they have available for managing tokens. However, I do not know any details regarding what exactly they are planning at this time. Once I learn more I will be sure to update this thread.

stan
Level 3 Contributor

Ok. To understand clearly. Every time I request access token I actually will get new refresh token correct?

This new refresh token is valid but also the previous before the request also continues to be valid?

Some more questions:

In Azure AD MFA there is setting:

Allow users to remember multi-factor authentication on devices they trust
Days before a device must re-authenticate (1-60):

If that is enabled this actually restricts the validity of the token not to 90 days but to whatever is set. Is this bug or undocumented design?

 

Can we also get some reccomendation how often we should replace the refresh token? Every day? Every week? Every month?

sergesettels
Level 2 Contributor

The refreshtoken will expire after 90 days. So even if you store it like every 10 days you will be good.

 

But you should store the received tokens every time when the tokens have changed (when the process actually went to the authentication servers) . Since the regular tokens are valid for 24 hours AquireTokenSilent will not go to the server until a new token is needed. If you do not store the token your process might go to the servers on every request.

 

Hope this helps anybody with similar problems

cblackuk
Level 2 Contributor

Literally had the same issue just now:

 

AADSTS700082: The refresh token has expired due to inactivity. The token was issued on 2019-01-25T11:59:32.0690372Z and was inactive for 90.00:00:00.
Trace ID: 8856fa3c-d840-426a-85b4-4954e16c2600
Correlation ID: 122975b3-9650-47da-bed3-a3f6e11bca35
Timestamp: 2019-04-25 16:38:07Z

 

This is a massive issue from a CSP perspective.

 

The token is being used to get access tokens like 500 times a day and yet it was "inactive" for 90 days.

 

Can somebody comment on this please?

idwilliams
Moderator

@cblackukand @stan 

 

This is happening because the refresh token has expired. The error being returned is a bit misleading and I believe that has caused some confusion. To better explain what is happening and what can be done it is important to understand that a single refresh token is only valid for 90 days. This means you can either perform the consent process every 90 days or implement the appropriate automation. Each time you request a new token from Azure AD a new refresh token is returned as well. If you were looking to automate the refresh of the refresh token, you would want to replace the existing refresh token value with a new one returned when you request a new access token on a set interval. Some partners are doing this once a week while others are doing it once a month. I hope that this helps!  

HenningT
Visitor 1

Same thing happened here on Monday.  The documentation is obviously not entirely correct, as the lifespan of the refresh token is fixed at 90 days, no matter how much it is used.  In order to have token based authentication working for more than the initial 90 days, you need to periodically refresh your token store with new refresh tokens.

 

As long as your current tokens have not expired, you can get new ones by calling the New-PartnerAccessToken cmdlet and update your store with the refreshtoken part of the token returned by the cmdlet.  It is a good idea to write a scheduled job performing this task for all your tenants on a regular basis.

 

Unfortunately, I believe you have to go through the consent process again in order to get valid refresh tokens again and get the whole thing rolling.  I just completed this for our 34 customer tenants, and yes: It was deadly boring 🙂

stan
Level 3 Contributor

@idwilliams  Can we get answer on this thread also? Why is this happening?

cginsight
Visitor 1

We have exactly the same problem.

 

Would someone from MS please look into this issue? The MS specification for the refresh token does NOT match the implementation. This needs to be fixed asap.