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 ?
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
.
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