After following an online tutorial to use token based authentication using OWIN, I managed to get my test app authenticating against a hard coded username/password, as the demo did.
However, now I want my model from my web application to be used.
My authentication happens, as the demo said, in this bit of code.
namespace UI
{
public class AuthorisationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated(); // Means I have validated the client.
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Here we validate the user...
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
if (context.UserName == "user" && context.Password == "password")
{
identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
identity.AddClaim(new Claim("username", "user"));
identity.AddClaim(new Claim(ClaimTypes.Name, "My Full Name"));
context.Validated(identity);
}
else
{
context.SetError("Invalid grant", "Username or password are incorrect");
return;
}
}
}
}
I have a WebAPI controller, which I receive a model from, and ... not sure how to call the above code, from my webapi controller. At the moment, the code above expects a call to myurl/token - that was defined in the startup code.
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Enables cors origin requests.
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// Config OAuth authorisation server;
var myProvider = new AuthorisationServerProvider();
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true, // Live version should use HTTPS...
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = myProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
}
}
So, I'm guessing the url from my webapi call should be /token? So, in my (Knockout View model) code on my UI, I tried this:
Login()
{
var data = {
username : this.login.emailAddress(),
password : this.login.password(),
RememberMe: this.login.rememberMe(),
grant_type: "password"
}
return $.ajax({
type: "POST",
data: data ? JSON.stringify(data) : null,
dataType: "json",
url: "/token",
contentType: "application/json"
}).done((reply) => {
alert("Done!");
});
}
But, I get an exception:
“error”: “unsupported_grant_type”
In 'Postman', I am able to authenticate the hard coded username/password.
But I am not sure how to wire up my api call from my UI, to authenticate.
I was hoping to create a 'Login' method on my api controller (ASP.Net WebAPI), like this:
[Route("login"), HttpPost, AllowAnonymous]
public ReplyDto Login(LoginRequest login)
{
ReplyDto reply = _userService.Login(login.Email, login.Password);
return reply;
}
So, my _userService checks if the user is in the database... if so, call my OAuth authentication here passing a few parameters. But not sure that's possible. Can I call my authentication from this api method? I'd need to remove the /token bit though.
You don't need to create a Login method since you already have it. It's http://localhost:1234/token. This is will generate a token if the user exists and if the password is correct. But get this behaviour you need to implement your own AuthServerProvider by deriving from OAuthAuthorizationServerProvider
public class DOAuthServerProvider : OAuthAuthorizationServerProvider
and then you would override a method to implement your logic:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
try
{
string allowedOrigin = context.OwinContext.Get<string>(DOAuthStatic.ALLOWED_CORS_ORIGINS_KEY);
if (allowedOrigin != null)
{
context.OwinContext.Response.Headers[DOAuthStatic.CORS_HEADER] = allowedOrigin;
}
DAuthenticationResponse authResponse = await _authRepository.Authenticate(context.UserName, context.Password);
if (!authResponse.IsAuthenticated)
{
context.SetError(OAuthError.InvalidGrant, $"{(int)authResponse.AuthenticateResult}:{authResponse.AuthenticateResult}");
return;
}
if (authResponse.User.ChangePasswordOnLogin)
{
_userAuthenticationProvider.GeneratePasswordResetToken(authResponse.User);
}
IDictionary<string, string> props = new Dictionary<string, string>
{
{
DOAuthStatic.CLIENT_NAME_KEY, context.ClientId ?? string.Empty
}
};
ValidateContext(context, authResponse, props);
}
catch (Exception ex)
{
DLogOAuth.LogException(ex, "DCO0407E", "OAuthServerProvider - Error validating user");
throw;
}
}
You are almost there, you just need to do two more steps:
Here is a great series of tutorials that explains everything really well: Token based authentication (way better than I have :) )
Change the Content Type "application/json" to "application/www-form-urlencoded"
You are Sended Data in Postman "application/www-form-urlencoded" format. But in Your Code Using "application/Json" the Content Type Mismatch. So,the Data is Not Send Proper Format.
You Can Change If it's Working Fine.
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