I am attempting to implement OWIN bearer token authorization, and based on this article. However, there's one additional piece of information I need in bearer token that I don't know how to implement.
In my application, I need to deduce from the bearer token user information (say userid). This is important because I don't want an authorized user from being able to act as another user. Is this doable? Is it even the correct approach? If the userid is a guid, then this would be simple. It's an integer in this case. An authorized user can potentially impersonate another just by guessing / brute force, which is unacceptable.
Looking at this code:
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (AuthRepository _repo = new AuthRepository())
{
IdentityUser user = await _repo.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
context.Validated(identity);
}
}
I would think that it is possible to override the authorization / authentication to accommodate what I need?
On a side note, if you want to set a custom error message you'll have to swap the order of the
context.Rejected
andcontext.SetError
.If you place
context.Rejected
aftercontext.SetError
then the propertycontext.HasError
will be reset to false therefore the correct way to use it is:It seems there's something missing in your code.
You're not validating your client.
You should implement ValidateClientAuthentication and check your client's credentials there.
This is what I do:
A good article full of details can be found here.
A even better explanation can be found in this blog series.
UPDATE:
I did some digging and webstuff is right.
In order to pass
errorDescription
to the client we need to Rejected before we set the error withSetError
:or we can extend it passing a serialized json object in the description:
With a
javascript/jQuery
client we could deserialize the text response and read the extended message:Just to add on to LeftyX's answer, here's how you can completely control the response being sent to the client once the context is rejected. Pay attention to the code comments.
Based on Greg P's original answer, with some modifications
Step1: Create a class which will act as your middleware
namespace SignOnAPI.Middleware.ResponseMiddleware {
Step2 : Create the extensions class (Can be omitted).
This step is optional, can be modified to accept options that can be passed to the middleware.
Step3: Modify
GrantResourceOwnerCredentials
method in yourOAuthAuthorizationServerProvider
implementationStep4: Use this middleware in the startup class