Base solution for your next web application
Open Closed

RefreshTokenAPI throwing 500 Error , 401 errors in PROD env #12629


User avatar
0
omkarchoudhari created

We are using ASP.NET Zero template version 10.1.0 with Angular as the front end.

We have a mobile application that calls ASP.NET Core APIs. To access the APIs, the mobile app calls the TokenAuth - Authenticate method to retrieve an access token. When the token expires, it generates a new refresh token using the RefreshToken API and uses the renewed token to continue calling the APIs.

However, based on our observations, in PROD env, within a 24-hour window, there are approximately 170 refresh token requests that are failing. We are unable to figure out why refresh token is throwign 500 errors. Also, due to this, we are also getting 401-unauthorized errors on customer mobile app. Can you please guide us to fix these issues?

Markdown is supported
Copy & paste or drag & drop images (max 30 MB per image)

1 Answer(s)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @omkarchoudhari

    We apologize for the delayed response. We wanted to review the issue carefully before replying.

    Thank you for the detailed information. Based on the Application Insights data you shared, there appear to be two primary exception types causing the 500 errors on POST TokenAuth/RefreshToken:

    1. InvalidDataContractException (41 occurrences) This exception typically occurs during refresh token deserialization. The most common causes are:

      • Truncated refresh tokens: In your screenshot, the refresh token is being sent as a query string parameter (?refreshToken=eyJhb...). JWT tokens can exceed common URL length limits (e.g., IIS default is 2048 characters for query strings), or be truncated by reverse proxies/load balancers. This can corrupt the token before it reaches the server. Recommendation: Send the refresh token in the request body, not as a query string parameter.

      • Corrupted tokens: If the mobile application stores the refresh token incorrectly (e.g., partial persistence, encoding issues, trimming), the server will fail to deserialize it.

      Action: In Application Insights, go to Failures > Exceptions, open the InvalidDataContractException entries, and review the full stack trace and inner exception details. Also verify that the mobile app is sending the complete, unmodified refresh token.

    2. TaskCanceledException (19 occurrences) This usually indicates that the client disconnected before the server completed processing. In most cases, this is secondary behavior for example, the mobile app times out while waiting for a response or retries the request, canceling the original one. This is likely a symptom rather than the root cause.

    3. Critical Setting: AllowOneConcurrentLoginPerUser

      In ASP.NET Zero, if the setting App.UserManagement.AllowOneConcurrentLoginPerUser is enabled (true), each successful authentication resets the user’s SecurityStamp. This invalidates all previously issued access and refresh tokens for that user.

      Additionally, inside the RefreshToken method, when this setting is enabled, the SecurityStamp is updated again during refresh:

      if (AllowOneConcurrentLoginPerUser())
      {
          await _userManager.UpdateSecurityStampAsync(user);
          await _securityStampHandler.SetSecurityStampCacheItem(user.TenantId, user.Id, user.SecurityStamp);
      }
      

      This can create a race condition. If multiple refresh requests occur concurrently (for example, several API calls triggering token refresh at the same time in the mobile app), the first request updates the SecurityStamp, and subsequent requests fail because the token’s SecurityStamp claim no longer matches.

      Action:

      • Check whether AllowOneConcurrentLoginPerUser is enabled in Host Settings or Tenant Settings.
      • If single session enforcement is not required, consider disabling it.
      • If it must remain enabled, ensure the mobile app serializes refresh requests (i.e., only one refresh call at a time, protected by a mutex/lock).
    4. Remaining 500 Errors (approximately 110 cases)

      The remaining failures are likely caused by the generic catch block inside the RefreshToken method:

      catch (Exception e)
      {
          throw new AbpValidationException("Refresh token is not valid!" + e);
      }
      

      This wraps various underlying issues (e.g., SecurityStamp mismatches, token validation failures, signing key issues) into AbpValidationException.

      Action: In Application Insights, filter by AbpValidationException with the message "Refresh token is not valid!" and inspect the inner exception details to identify the exact root cause.

    Recommended Next Steps:

    1. Verify the AllowOneConcurrentLoginPerUser setting in the AbpSettings table and disable it if not required.
    2. In Application Insights, review full stack traces under Failures > Exceptions, filtered by POST TokenAuth/RefreshToken.
    3. Ensure the mobile app sends the refresh token in the request body, not as a query parameter.
    4. Implement a refresh queue/mutex mechanism in the mobile app to prevent concurrent refresh requests.
    5. Temporarily enable DEBUG level logging for TokenAuthController to capture more detailed diagnostics.

    These steps should help you isolate whether the issue is related to token truncation, concurrent refresh requests, security stamp invalidation, or token validation failures.

    Additionally, please note that our project is currently running on ASP.NET Zero version 15.1, while your implementation is on 10.1.0. There may be improvements or changes in the authentication and refresh token pipeline between these versions, so reviewing the related release notes and migration documentation could also help identify version specific differences.

    Please let us know the inner exception details if the issue persists, and we can further narrow down the root cause.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)