trinvh
trinvh

Reputation: 1580

ASP.NET Core Openiddict throws "An OpenID Connect response cannot be returned from this endpoint"

I follow instruction in openiddict server example using password flow from https://github.com/openiddict/openiddict-samples/tree/master/samples/PasswordFlow but have no success.

It throws InvalidOperationException: An OpenID Connect response cannot be returned from this endpoint at route /connect/token:

return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);

Postman params:

I spent my day for researching but there is no information about cannot be returned from this endpoint exception. And many people can run openiddict example except me.

Here is apart of Startup.cs:

services.AddEntityFrameworkSqlite()
    .AddDbContext<MisapayContext>(options =>
    {
        options.UseOpenIddict<int>();
    });

    //....

    services.AddOpenIddict<int>()
    .AddEntityFrameworkCoreStores<MisapayContext>()
    .DisableHttpsRequirement()
    .EnableTokenEndpoint("/connect/token")
    .EnableLogoutEndpoint("/connect/logout")
    .EnableUserinfoEndpoint("/connect/userinfo")
    .UseJsonWebTokens()
    .AllowPasswordFlow()
    .AllowRefreshTokenFlow()
    .AddEphemeralSigningKey();

services.AddMvc(config =>
{
    config.Filters.Add(new ApiExceptionFilter());
}).AddJsonOptions(options =>
{
    options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
    options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local;
});

Edited: I think problem is OpenIdConnectRequest, it can not be binded if use:

OpenIddictBuiler.AddMvcBinders()

Will throws The OpenID Connect request cannot be retrieved from the ASP.NET context.`

Otherwise, remove it, OpenIdConnectRequest in AuthorizationController can get properly. And I can get request information such as username, password grantType etc... Strange... right?

Some other information:

Any help will be appreciated!

Upvotes: 5

Views: 4970

Answers (1)

K&#233;vin Chalet
K&#233;vin Chalet

Reputation: 42010

Okay, here's what's happening:

  • You've configured OpenIddict to use /connect/token as the token endpoint address.
  • The token request you send via Postman points to /connect/token/, which is actually a totally different URL (/connect/token != /connect/token/).
  • Since the address differs from the registered endpoint path, OpenIddict doesn't handle the request and refuses to consider it as a token request.
  • For some reasons, MVC accepts to handle your /connect/token/ request and invokes the Exchange action, even though the route doesn't match the requested URL.
  • Since you haven't registered the OpenIddict MVC binder in the MVC options, MVC uses its default binder to construct the OpenIdConnectRequest object, which allows the OpenIdConnectRequest.GrantType parameter to be resolved from the invalid grantType parameter (it wouldn't happen with the dedicated OpenIddict binder).
  • Your token endpoint action ends up calling SignIn to return a token response.
  • Under the hood, OpenIddict detects that you called SignIn outside the normal token request processing - since it didn't consider the request as a token request, due to the paths difference - and aborts this unsafe operation by throwing an InvalidOperationException.

I'll ping the MVC folks to make sure they are aware of this bug.

Edit: after some research, it looks like this behavior is "by design" and was inherited from ASP.NET MVC. I opened a feature request in the aspnet/Mvc repository to add a new way to use "strict comparison" for routes matching.

Upvotes: 6

Related Questions