-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Describe the bug
Since updating to OC 2.1.7 we occasionally see this error in our application that relies on the Orchard Core OpenID Server:
2025-10-31 00:00:59.9707|Error||Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler|Exception occurred while processing message. |remoteip: 10.232.0.42 |session-id:
[OpenIdConnectProtocolException] Message contains error: 'invalid_grant', error_description: 'The specified token is invalid.', error_uri: 'https://documentation.openiddict.com/errors/ID2004'.
error: invalid_grant
error_description: The specified token is invalid.
error_uri: https://documentation.openiddict.com/errors/ID2004
at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.RedeemAuthorizationCodeAsync(OpenIdConnectMessage tokenEndpointRequest)
at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()
--- End of stack trace for exception handler ---
at Microsoft.Extensions.Logging.Logger.Log[TState](LogLevel logLevel, EventId eventId, TState state, Exception exception, Func`3 formatter)
at Microsoft.Extensions.Logging.LoggerMessage.<>c__DisplayClass8_0.<Define>g__Log|0(ILogger logger, Exception exception)
at Microsoft.Extensions.Logging.LoggingExtensions.ExceptionProcessingMessage(ILogger logger, Exception ex)
After chasing this for a while via increased logging on the Orchard Core side (OpenIddict logging is tough as it's either incredibly verbose or very sparse unless you apply filters that are tricky to get right until you know what you're looking for), we've determined that the error results from the call to the /userinfo endpoint failing.
The failure looks like this in the OC logs:
2025-11-05 00:00:54.4990|6141|INFO|OpenIddict.Server.OpenIddictServerDispatcher|The response was successfully returned as a challenge response: {
"error": "invalid_token",
"error_description": "The specified token is invalid.",
"error_uri": "https://documentation.openiddict.com/errors/ID2004"
}. |url: https://advantageacs.acsdomain.advantagecs.com/launchpad/connect/userinfo |action: Me|trace: 00-34884212f9cdb892aba0192f473e1d14-3fec4caf9896f05b-00|user: |ip: 10.232.2.84
It fails because the token isn't found:

However, I was able to determine the token identifier that it was looking for via the OC logs:
2025-11-05 00:00:54.4520|6001|TRACE|OpenIddict.Server.OpenIddictServerDispatcher|The token '[redacted]' was successfully validated and the following claims could be extracted: iss:... updated_at: 1715097600, oc:entyp: user, sub: 4r19qa0kcjrfw5171z4wcmnqnp, ..., oi_au_id: 129982164a6c4bdc8a8f9f0624e94d1b, client_id: advantage-ui-UI-PERF, **oi_tkn_id: 72668b8758a049e381de54ea6f829677**, oi_tkn_typ: urn:ietf:params:oauth:token-type:access_token. |url: https://advantageacs.acsdomain.advantagecs.com/launchpad/connect/userinfo |action: Me|trace: 00-34884212f9cdb892aba0192f473e1d14-3fec4caf9896f05b-00|user: |ip: 10.232.2.84|OpenIddict.Server.OpenIddictServerHandlers+Protection+ValidateIdentityModelToken.HandleAsync
And that token actually is in the database now:

It looks like this is almost certainly a timing issue as the call to the token endpoint to exchange the authorization code for a token is immediately followed by a call to the userinfo endpoint to exchange the access token for additional user information (all handled by the Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler).
It appears that there is effectively a race condition that was introduced by Replace unnecesary calls to SaveChangesAsync by FlushAsync
Previously SaveChangesAsync was used in the TokenStore. This would ensure that the token was committed to the DB immediately. Now FlushAsync is used which leaves the commit to happen when the YesSQL Session is disposed. I don't think that is guaranteed to happen before the response is parsed by the OpenID client which immediately issues the follow-on /userinfo endpoint request.
Orchard Core version
Reproduced in 2.1.7, 2.2.0, 2.2.1
To Reproduce
See above. Unfortunately, I don't have simple repro steps using the orchard repo. You need to set up an OpenID client that users the authorization code flow and then hit it many times and you'll eventually see the problem. It happens rarely, but several times per day for us.
Expected behavior
An access token should be immediately usable when it is returned to the caller.
Logs and screenshots
See above.