Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET JSON Web Token "401 Unauthorized"

I'm using decoupled resource and authentication servers. When I successfully get JSON Web Token, I check it with jwt.io and everything is ok with token format and it's secret.

Request is with authorization header:

Authorization: Bearer TOKEN_HERE

Response is always "401 Unauthorized":

{
  "message": "Authorization has been denied for this request."
}

Here is my Startup.cs from resource server

using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;
using Newtonsoft.Json.Serialization;
using Owin;
using System.Web.Http;
using Test.Database;
using Test.Infrastructure;
using Microsoft.WindowsAzure.ServiceRuntime;

[assembly: OwinStartup(typeof(Test.API.Startup))]
namespace Custodesk.API
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.CreatePerOwinContext(() => 
                ApplicationDbContext.Create(RoleEnvironment.GetConfigurationSettingValue("SqlConnectionString")));
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

            GlobalConfiguration.Configuration.SuppressDefaultHostAuthentication();

            ConfigureOAuthTokenConsumption(app);

            GlobalConfiguration.Configure(config =>
            {
                //global filters
                config.Filters.Add(new AuthorizeAttribute());

                // Web API routes
                config.MapHttpAttributeRoutes();
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "{controller}/{action}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );

                config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

            app.UseCors(CorsOptions.AllowAll);

            app.UseWebApi(GlobalConfiguration.Configuration);
        }

        private void ConfigureOAuthTokenConsumption(IAppBuilder app)
        {
            var issuer = "http://localhost";
            var audience = "Universal_application";
            var secret = Helper.GetHash("helper_class_to_get_the_same_hash_as_authentication_server");

            // Api controllers with an [Authorize] attribute will be validated with JWT
            app.UseJwtBearerAuthentication(
                new JwtBearerAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] { audience },
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
                    {
                        new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                    }
                });

        }
    }
}

Here is an example of token decrypted:

{
  "typ": "JWT",
  "alg": "HS256"
}
{
  "nameid": "b22a825e-60ce-45ed-b2cb-b2ee46a47936",
  "unique_name": "begunini",
  "role": [
    "Owner",
    "Admin",
    "ManagerViewer"
  ],
  "iss": "http://localhost",
  "aud": "Universal_application",
  "exp": 1454876502,
  "nbf": 1454876202
}

I've checked the Secret and it's the same on both sides (auth and resource servers). Audience matches, issuer also. Already tried to downgrade System.IdentityModel.Tokens.Jwt to version 3.0.2 but no luck

I guess there is some problem in Configuration order, but nothing helped.

Any ideas ?

like image 480
Begunini Avatar asked Feb 07 '16 21:02

Begunini


1 Answers

TL;DR: have you tried removing GlobalConfiguration.Configuration.SuppressDefaultHostAuthentication()?

When using this method, Web API removes the user principal created and added to the OWIN context by the host or by the middleware registered before Web API (in your case, by the JWT bearer middleware).

This method is intended to be used with HostAuthenticationFilter or HostAuthenticationAttribute, that directly invokes the authentication middleware corresponding to the specified authentication type and persists the resulting user principal in the OWIN context.

Since you're using SuppressDefaultHostAuthentication without HostAuthenticationAttribute, Web API always sees unauthenticated requests, and that's why they are rejected by AuthorizeAttribute.

like image 105
Kévin Chalet Avatar answered Sep 25 '22 17:09

Kévin Chalet