Calling HttpContext.GetUserAccessTokenAsync makes the number of authentication cookies increase
EnricoMassone opened this issue · comments
Context
- this issue refers to an ASP.NET core 2.2 MVC web application
- this application is an OIDC client for which the hybrid flow is used
- we use another ASP.NET core 2.2 web application based on IdentityServer4 as the identity provider
- the client application references IdentityModel.AspNetCore version 2.0.0 to manage the user access token renewal
- the user authentication in the client MVC application is based on authentication cookies. ASP.NET core automatically split our authentication cookie in chunks. In all the customers and tesing environment we have 3 authentication cookies: two of them are the actual chunks, the third one is a cookie that keeps track that there are 2 actual chunks. This is the standard behavior of the ASP.NET core cookie middleware, as far as I understand.
Issue description
One of the pages of the client MVC application makes an AJAX call to an action method whose purpose is ensuring that the user access token is not expired. This AJAX call is authenticated by sending authentication cookies along with the request itself.
This is the implementation of the called action method:
[ApiExplorerSettings(IgnoreApi = true)]
[Route("boapi/refreshAccessToken")]
[Authorize]
public class RefreshAccessTokenController : NonCachableController
{
[HttpPost("")]
public async Task<IActionResult> RefreshAccessToken()
{
await HttpContext.GetUserAccessTokenAsync();
return Ok();
}
}
As you can see, we ensure that the user access token is not expired by calling the GetUserAccessTokenAsync extension method
Expected behavior of the AJAX request
In all of our testing and customer environments (but the one for which I'm writing this issue) the AJAX call described above does not change the number of chunks for the user authentication cookie. We have configured Identity Server 4 so that the user access token expires after one hour. So if a user logs in and one hour later the AJAX request is performed the user access token is refreshed in the backend and the corresponding HTTP response sets new cookies for the user. Based on my understanding, the user access token is serialized as part of the authentication cookie, so whenever the user access token changes the authentication cookie itself is changed. This should be the code responsibile for setting the new authentication cookie in the HTTP response.
This is a screen shot taken from one of our testing environment: as you can notice the HTTP request sends 3 cookies to the backend endpoint and the corresponding HTTP response sets the exact same 3 cookies. This is the standard and expected behavior.
What is going wrong
In one of our production environment, when the described AJAX call is performed, we observe an unexpected growth of the number of authentication cookies. The request cookies are 3, but the corresponding cookies in the response are much more (7 in the case describe by the following screenshot, but this seems to be randomic). This growth of the number of cookies, when reiterated for several times, takes the total number of authentication cookies to a value of 12 or 13: at that point all the HTTP request performed by the browser fail and return a 400 response status code (reqeust cookie too large). At that point the application is no more usable and the user needs to close the browser, to reopen it and to log in again.
This is a screenshot taken from the offending production environment. As you can see there are 3 request cookies and 8 response cookies.
Do you have any idea of what's happening ?
I can't understand why the number of chunks created by ASP.NET core for the authentication cookie grows after refreshing the user access token. This doesn't make sense to me, because the user identity does not change: the only think that is changing is the user access token.
Am I missing anything ?
Do you have any idea of the possible root cause of this issue ? Any tip on which I can possibly investigate on would be really appreciated.
Notice that I'm not able to constantly reproduce this issue in other environment, so I would exclude a bug in the IdentityServer.AspNetCore library. I'm quite sure that the issue is related to some corner case of this production environment, but I don't know where to start to find it.
Thanks for helping !
I don't know.
FWIW - I removed ASP.NET Core 2.x support in the latest version. If you want to continue using this version, please clone the source code and integrate in your solution.
I don't know.
FWIW - I removed ASP.NET Core 2.x support in the latest version. If you want to continue using this version, please clone the source code and integrate in your solution.
Hi, thanks for replying.
We are actually using version 2.0.0 of the package. It is compatible with ASP.NET core 2.2, isn't it?
I noticed that version 3.0.0 removed the compatibility with ASP.NET core 2.x. We are actually planning an upgrade of the whole project to ASP.NET core 3.1.
Closing - let me know when you had a chance to use a more recent version of ASP.NET Core.
Closing - let me know when you had a chance to use a more recent version of ASP.NET Core.
Hi,
I've patched the customer environment with a new release, which uses client access tokens instead of user access tokens. By doing so the issue disappeared. We did so in order to quickly provide the customer with a working solution.
I would like to deploy the old version of the code to the customer staging environment in order to further investigate how the user identity is changed (at the claims level) when HttpContext.GetUserAccessTokenAsync
is called. Unfortunately I'm not able to reproduce the same issue in our test environment, so the only chance to reproduce the issue is using one of the customer environments. Put another way, the investigation is currently stuck.
I'll comment here with the results of my investigation if I'll be allowed to carry on further testing on the customer environment.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue.