I have created a new WebAPI solution in visual studio and am playing around with the code to try and understand whats going on.
I have a test API thats all up and running with an Authorization controller and another controller that implements all the actual functionality.
The controllers (API) all work by receiving JSON and replying with JSON, with the exception of the /Token request.This has to be:
Content-Type: application/x-www-form-urlencoded
otherwise I just get an error back.
The section of code that creates this endpoint appears to be this:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = false
};
Calling it like this results in a 200 Success response, with a Bearer token:
$("#token_button").click(function ()
{
var username = $("#token_email").val();
var password = $("#token_password").val();
postData("Token", "grant_type=password&username=" + username + "&password=" + password, "application/x-www-form-urlencoded", function (data)
{
user = data;
$("#feedback_display").html(user.access_token);
}, function ()
{
user = null;
});
});
Calling it like this results in a 400 Response:
$("#token_button").click(function ()
{
var username = $("#token_email").val();
var password = $("#token_password").val();
var data = {
"grant_type": "password",
"username": username,
"password": password
}
postData("Token", JSON.stringify(data), "application/json", function (data)
{
user = data;
$("#feedback_display").html(user.access_token);
}, function ()
{
user = null;
});
});
The response body is:
{"error":"unsupported_grant_type"}
The only difference here is the encoding used to transmit the request. Every where I look all the examples are using form encoding to request this token.
Placing a breakpoint on the code under /api/Account/ExternalLogin, never gets hit.
Is there a reason for this only accepting form encoding? and if not how can I change the controller to accept JSON?
Alternatively have I just done something stupid?
A new security design for MVC,Owin Authentication middleware,is recommended for higher security. The security features can be shared by other components which are hosted on OWIN. OWIN provides the underlying set of components to asp.net applications to enable, then to be flexible,portable,and lightweight.
The reason behind the use of application/x-www-form-urlencoded
as Content-Type
is simple: the OAuth2 specification (RFC 6749) requires this content type for token requests.
Any other content-type will break OAuth2 compliant clients compatibility. I advice you to not change this standard behavior.
Note
Please note that this:
postData("Token", data, "application/json", function (data)
{
//...
}
works just because you are not sending JSON at all! Even if you added application/json
as Content-Type
header your request body is serialized as form key-value pairs (the jQuery default object serialization in AJAX calls).
The default implementation of OAuthAuthorizationServerMiddleware
(more precisely the internally used OAuthAuthorizationServerHandler
) from Microsoft.Owin.Security.OAuth
just ignores the Content-Type
header and tries to read the request body as a form anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With