Activities of "yuxianglong"

Check the docs before asking a question: https://abp.io/docs/latest Check the samples to see the basic tasks: https://abp.io/docs/latest/samples The exact solution to your question may have been answered before, and please first use the search on the homepage.

Provide us with the following info: 🧐 Hint: If you are using the ABP Studio, you can see all the information about your solution from the configuration window, which opens when you right-click on the solution and click on the Solution Configuration button.

  • Exception message and full stack trace:
  • Steps to reproduce the issue:

Summary

With ABP Identity Session Management enabled together with Dynamic Claims, the OAuth password grant endpoint /connect/token can return 200 with a valid access_token (JWT signature/expiry are OK), but the immediately following API request fails with:

  • HTTP 401
  • error=invalid_token
  • error_description=SessionExpired

The failure happens because ABP cannot find the token’s session_id in the AbpSessions table at request time (IdentitySessionChecker log: "Could not find SessionId(...) in the database."). In our observations, the row may appear in AbpSessions shortly after, which suggests a commit/visibility timing issue rather than an invalid JWT.

Expected behavior

After /connect/token returns 200, any immediately subsequent API request using the new access token should pass Identity Session validation when Dynamic Claims is enabled.

Actual behavior

  1. POST /connect/token (password grant) returns 200 and returns access_token / refresh_token.
  2. The SPA/client immediately calls business APIs in parallel.
  3. Those APIs return 401 SessionExpired due to IdentitySessionChecker not finding the session_id in AbpSessions.
  4. Manual DB inspection sometimes shows the session_id row exists later.

Representative log text: "Could not find SessionId(<sid>) in the database." "The token is no longer valid because the user's session expired."

Root cause hypothesis (timing mismatch)

During the same /connect/token HTTP request:

  • OpenIddictCreateIdentitySession inserts the Identity Session row into AbpSessions.
  • OpenIddict then writes the token response body to the client.
  • The ambient request UnitOfWork commit (so the inserted AbpSessions row becomes visible) occurs later in the ASP.NET request pipeline.

As a result, the next HTTP request can start and validate session_id before the inserted row is committed/visible under the DB isolation level.

In some environments, reverse proxies/dev proxies may amplify the issue when the connection is closed after response flush, leading to an aborted request pipeline.

Reproduction outline

Environment conditions we observed:

  • ABP Identity Session Management enabled
  • Dynamic Claims enabled (IsDynamicClaimsEnabled = true)
  • OpenIddict password grant /connect/token
  • Client immediately calls protected APIs after receiving the token
  • Reverse proxy / dev proxy in front may affect timing (e.g. connection close behavior)

Related work / possible overlap

We found ABP Support issue #10850: https://abp.io/support/questions/10850/1050-regression-identity-session-invalid-after-second-re-authentication-in-same-browser-session--IdentitySessionChecker-cannot-find-just-created-SessionId-user-force-logged-out

That report focuses on regression after second re-authentication (sign-out + sign-in) and session revocation behavior in a browser session. Our case occurs right after a successful /connect/token response with an immediate next API call, without relying on the same “second re-auth” flow.

Current mitigation in our project (already deployed / verified)

In our integration, we implemented a mitigation by replacing the default OpenIddict Identity Session handler with a wrapper that commits the Identity Session earlier.

Behavior:

  • When handling OpenIddictServerEvents.ProcessSignIn, we execute the official OpenIddictCreateIdentitySession inside a new transactional UnitOfWork (requiresNew: true, isTransactional: true).
  • We call CompleteAsync(CancellationToken.None) immediately after the official handler runs, before OpenIddict writes the token response to the client.
public class OpenIddictCommitIdentitySessionHandler : IOpenIddictServerHandler<OpenIddictServerEvents.ProcessSignInContext>
{
    public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor
        .CreateBuilder<OpenIddictServerEvents.ProcessSignInContext>()
        .UseScopedHandler<OpenIddictCommitIdentitySessionHandler>()
        .SetOrder(100000)
        .SetType(OpenIddictServerHandlerType.Custom)
        .Build();

    private readonly OpenIddictCreateIdentitySession _createIdentitySession;
    private readonly IUnitOfWorkManager _unitOfWorkManager;

    public OpenIddictCommitIdentitySessionHandler(
        OpenIddictCreateIdentitySession createIdentitySession,
        IUnitOfWorkManager unitOfWorkManager)
    {
        _createIdentitySession = createIdentitySession;
        _unitOfWorkManager = unitOfWorkManager;
    }

    public async ValueTask HandleAsync(OpenIddictServerEvents.ProcessSignInContext context)
    {
        using var uow = _unitOfWorkManager.Begin(requiresNew: true, isTransactional: true);
        await _createIdentitySession.HandleAsync(context);
        await uow.CompleteAsync(CancellationToken.None);
    }
}

Result:

  • /connect/token still returns 200 normally, but the immediate next API calls no longer fail with SessionExpired.
  • This confirms the issue is a timing/commit visibility problem between token response output and IdentitySession persistence.

ABP version

10.5.0

Showing 1 to 1 of 1 entries
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on October 16, 2026, 14:19
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.