Owin Bearer Token Not Working for WebApi
Solution 1
You must configure the OAuth authorization server and OAuth bearer authentication before call UseWebApi on IAppBuilder. The following is from my program.
public void Configuration(IAppBuilder app)
{
app.UseFileServer(new FileServerOptions()
{
RequestPath = PathString.Empty,
FileSystem = new PhysicalFileSystem(@".\files")
});
// set the default page
app.UseWelcomePage(@"/index.html");
ConfigureAuth(app);
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute
(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.JsonFormatter.SerializerSettings =
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new YourApplicationOAuthProvider()
};
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication
(
new OAuthBearerAuthenticationOptions
{
Provider = new OAuthBearerAuthenticationProvider()
}
);
}
Solution 2
HttpConfiguration config = new HttpConfiguration();
app.UseNinjectMiddleware(NinjectContainer.CreateKernel);
app.UseNinjectWebApi(GlobalConfiguration.Configuration);
ConfigureOAuth(app);
WebApiConfig.Register(config);
//GlobalConfiguration.Configure(WebApiConfig.Register);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// app.UseWebApi(GlobalConfiguration.Configuration);
app.UseWebApi(config);
app.UseWelcomePage();
I tried this with ur sample application on github and it worked
Solution 3
In your provider you have to:
public override ValidateClientAuthentication(OAuthClientAuthenticationContext context)
{
//test context.ClientId
//if you don't care about client id just validate the context
context.Validated();
}
The reason for this is that if you don't override ValidateClientAuthentication and validate the context, it is assumed as rejected and you'll always get that error.
Ody
I am currently a senior Software Developer at Cyberspace Limited. I focus mainly on web technologies with a bit of Android Development Primary Languages: C#, Java, C++, Ruby, JavaScript Primary Frameworks: ASP.NET, Rails, AngularJS
Updated on July 09, 2022Comments
-
Ody almost 2 years
I have gone through loads of documentation on this, My google search shows that I've visited all the links on the first page
Problem Token Generation works fine. I configured it with a custom provider as such:
public void ConfigureOAuth(IAppBuilder app) { var usermanager = NinjectContainer.Resolve<UserManager>(); app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new AppOAuthProvider(usermanager) }); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); }
However when I call a protected URL and pass the bearer token, I always get:
How do I diagnose or fix the problem. If possible, how can I do the token validation myself
UPDATE Here is my AppOAuthProvider. Both Methods are called when I'm trying to mint a token but not when I'm trying to access a protected resource
public class AppOAuthProvider : OAuthAuthorizationServerProvider { private UserManager _user; public AppOAuthProvider(UserManager user) { _user = user; } public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); //Get User Information var getUser = _user.FindUser(context.UserName); if (getUser.Status == StatusCode.Failed) { context.SetError("invalid_grant", "The user name or password is incorrect."); return Task.FromResult<object>(null); } var user = getUser.Result; //Get Roles for User var getRoles = _user.GetRoles(user.UserID); if (getRoles.Status == StatusCode.Failed) { context.SetError("invalid_grant", "Could not determine Roles for the Specified User"); } var roles = getRoles.Result; var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim("UserID", user.UserID.ToString())); identity.AddClaim(new Claim("UserName", user.UserName)); foreach (var role in roles) { identity.AddClaim(new Claim(ClaimTypes.Role, role)); } context.Validated(identity); return Task.FromResult<object>(null); } }
UPDATE 2: Here is my Account Controller
[RoutePrefix("api/auth/account")] public class AccountController : ApiController { private UserManager _user; public AccountController(UserManager user) { _user = user; } [Authorize] [HttpGet] [Route("secret")] public IHttpActionResult Secret() { return Ok("Yay! Achievement Unlocked"); } }
UPDATE 3: Here is my Startup.cs
public partial class Startup { public void Configuration(IAppBuilder app) { app.UseNinjectMiddleware(NinjectContainer.CreateKernel); app.UseNinjectWebApi(GlobalConfiguration.Configuration); GlobalConfiguration.Configure(WebApiConfig.Register); ConfigureOAuth(app); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); app.UseWebApi(GlobalConfiguration.Configuration); app.UseWelcomePage(); } }