Base solution for your next web application
Open Closed

Clarity on refresh token implementation. #12513


User avatar
0
JapNolt created

We're using ASP.NET Zero version 13.1.1 and are now looking into enabling refresh token support. I'm new to this feature and have a few questions:

  • What’s the recommended way to revoke refresh tokens? Marking a user as inactive in our project still allows them to obtain new access tokens using an existing refresh token.
  • Is there a built-in way to detect refresh token reuse or abuse?
  • Are there any parts of the default refresh token implementation we should review or customize before enabling it for users?
  • Do SignalR connections to clients ever refresh to ensure the user is still valid?
Markdown is supported
Copy & paste or drag & drop images (max 30 MB per image)

6 Answer(s)
  • User Avatar
    0
    JapNolt created

    Just bumping this question...

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @JapNolt

    How to revoke refresh tokens?

    By default, marking a user as inactive (IsActive = false) will block new login attempts. However, any previously issued refresh tokens will still be valid, and can be used to obtain new access tokens. The reason is that the default refresh token validation logic does not check the user's active status or deletion state.

    Recommendation: We suggest customizing the refresh token validation logic to include the following checks before issuing a new access token:

    • Is the user active (IsActive = true)?
    • Has the user been deleted (IsDeleted = false)?
    • Is the user authorized to continue using the application (based on your custom logic)?

    Is refresh token reuse or abuse detected by default?

    No, the default implementation in ASP.NET Zero / ABP uses a basic token storage mechanism (such as AbpPersistedGrant). It does not include built in protection against refresh token reuse or abuse.

    Best Practice for Reuse Detection:

    • Implement one time use refresh tokens. That is, once a refresh token is used, it should be immediately invalidated (deleted from the store).
    • This prevents token reuse in the case of theft or interception.

    What should we review or customize before enabling refresh tokens?

    We recommend reviewing the following areas:

    • Token lifetimes: Check the values defined in AppConsts.
    • Client association: If you have multiple types of clients (e.g., web, mobile), consider scoping refresh tokens per client to avoid security risks from token leakage across applications.
    • Token persistence and cleanup: Make sure expired or invalidated tokens are removed periodically if you're storing them in a custom store.

    Do SignalR connections validate user status after connection?

    No. When a SignalR connection is established, it is validated using the access token only at the time of connection. After that:

    • The connection remains open until the token expires or the connection is dropped.
    • If the user is later marked as inactive (IsActive = false), existing SignalR connections are not affected.
    • Once the token expires, the connection is closed and a new token will be required at which point user validity checks can be re applied.

    If you’re planning to enable refresh token support in a production environment, we recommend reviewing and customizing the above behaviors to meet your security and business requirements.

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    JapNolt created

    Thank you for the response. I noticed when using an external authentication provider refresh tokens are by default not saved client side. What the reasoning was for this design?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @JapNolt,

    Yes, in ASP.NET Zero, by default when you log in using external authentication providers (Google, Microsoft, etc.), the refresh token is not stored on the client side. There are two main reasons for this:

    • Refresh tokens obtained from external providers are often long lived, and if stolen, an attacker could gain prolonged access to a user’s account.
    • Storing a refresh token in potentially insecure environments like browsers exposes it to XSS or local storage manipulation attacks.

    Default Architectural Choice

    • For external provider logins, ASP.NET Zero keeps the access token short lived and recommends retrieving a new token from the external provider via secure server to server communication when needed.
    • This way, the refresh token is stored only in the secure server environment and never sent to the client.

    What you can do

    • If your business scenario truly requires storing the refresh token on the client side (e.g., in more secure environments like mobile apps), you can customize the login method to pass rememberMe = true along with the refresh token value.
    • For web clients, however, we recommend keeping the refresh token on the backend and implementing a “silent refresh” flow where the frontend requests a renewed access token from your backend when needed.
    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    JapNolt created

    Not storing the external auth providers refresh token makes sense. Though I was referring to the refresh token issued by asp.netzero returned in externalAuthenticate, not the refresh token from the external authentication provider. Why isn't the refresh token issued by asp.netzero stored client side after authenticating with an external auth provider?

    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi @JapNolt

    In ASP.NET Zero, after ExternalAuthenticate, the refresh token issued by our own system is not stored client side by default because the default login flow only returns a refresh token to the client in the standard username, password scenario.

    Why is it designed this way?

    1. Different flow expectations

      • In normal login, a refresh token is returned because that endpoint is optimized for long lived, token based sessions.
      • In external login, the default assumption is that the user experience relies on a one time sign in + short lived access token model.
      • The default design expects new access tokens to be obtained by securely re contacting the external provider, so the client never receives the ASP.NET Zero refresh token.
    2. Additional security layer

      • In external logins, the primary authentication authority is the external provider (Google, Microsoft, etc.).
      • Giving our own refresh token to the client would potentially allow it to be used for a longer period. If it were stolen via XSS or local storage attacks, both our system’s and the external provider’s session security could be compromised.
    3. Often unnecessary

    • Many external login scenarios use a silent external reauth or server side stored refresh token approach to keep sessions alive.
    • Because of this, the default flow simply doesn’t return our refresh token to the client.

    What you can do

    • If your business case requires storing the ASP.NET Zero refresh token client side after an external login, you can customize the ExternalAuthenticate method to return it in the same way as the standard Authenticate flow.
    • You can also guard this behavior with a flag like rememberClient and only enable it in trusted environments (e.g., mobile apps).
    Markdown is supported
    Copy & paste or drag & drop images (max 30 MB per image)