Authorization_code grant flow on Owin.Security.OAuth: returns invalid_grant

梦想的初衷 提交于 2019-12-04 07:23:46

Here is what I got working. I'm not completely comfortable with that solution, but it works and should help others to fix their issues.


So, the issue is that I didn't set the AuthorizationCodeProvider property. When a request with grant_type=authorization_code is received, the code must be validated by that code provider. The framework assumes that the code was issued by that code provider, but that's not my case. I get it from another server and have to send the code back to it for validation.

In the standard case, where you are also the one issuing the code, the link provided by RajeshKannan describes everything you have to do.

Here is where you have to set the property:

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString(Paths.TokenPath),
    Provider = new SampleAuthProvider(),
    AuthorizationCodeProvider = new MyAuthorizationCodeProvider ()
}

And the declaration of the MyAuthorizationCodeProvider class:

internal class MyAuthorizationCodeProvider : AuthenticationTokenProvider
{
    public override async Task ReceiveAsync(
        AuthenticationTokenReceiveContext context)
    {
        object form;
        // Definitely doesn't feel right
        context.OwinContext.Environment.TryGetValue(
                "Microsoft.Owin.Form#collection", out form); 
        var redirectUris = (form as FormCollection).GetValues("redirect_uri");
        var clientIds = (form as FormCollection).GetValues("client_id");
        if (redirectUris != null && clientIds != null)
        {
            // Queries the external server to validate the token
            string username = await MySsoService.GetUserName(context.Token,
                                                             redirectUris[0]);
            if (!string.IsNullOrEmpty(username))
            {
                var identity = new ClaimsIdentity(new List<Claim>()
                {
                    // I need the username in  GrantAuthorizationCode
                    new Claim(ClaimTypes.NameIdentifier, username) 
                }, DefaultAuthenticationTypes.ExternalBearer);

                var authProps = new AuthenticationProperties();

                // Required. The request is rejected if it's not provided
                authProps.Dictionary.Add("client_id", clientIds[0]); 

                // Required, must be in the future
                authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1); 

                var ticket = new AuthenticationTicket(identity, authProps);
                context.SetTicket(ticket);
            }
        }
    }
}

I had the same error. Things I was missing:

  • Specify OAuthAuthorizationServerOptions.AuthorizationCodeProvider according to the documentation.
  • Specify the same client_id as a GET-parameter when making a request to the token endpoint as you did when you received the authorization_code.
  • Override OAuthAuthorizationServerProvider.ValidateClientAuthentication and in this method call context.TryGetFormCredentials. This sets the property context.ClientId to the value from the client_id GET-parameter. This property must be set, otherwise you'll get the invalid_grant error. Also, call context.Validated().

After doing all of the above, I could finally exchange the authorization_code to an access_token at the token endpoint.

Make sure that you have configured your authorization server options. I think you should provide your authorize end point details:

 AuthorizeEndpointPath = new PathString(Paths.AuthorizePath)

In the below link, the authorization code grant will be explained in detail and it lists the method which were involved in authorization code grant life cycle.

Owin Oauth authorization server

Thanks scenario, My code was missing the following two required values. Posted here in case others find it useful:

            // Required. The request is rejected if it's not provided
            authProps.Dictionary.Add("client_id", clientIds[0]); 

            // Required, must be in the future
            authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1); 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!