Owin Bearer Token Not Working for WebApi

23,877

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.

Share:
23,877
Ody
Author by

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, 2022

Comments

  • Ody
    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: Token Request

    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();
        }
    }