Search code examples
authenticationasp.net-web-apiowinaccess-tokenauth0

Configuring Web Api 2 as Resource Server using OWIN


Trying to configure my Web Api as Resource Server. My client logs into Auth0 and gets Bearer token, so Authorization Server is Auth0 not my Api. Then they send request along with the Bearer token to my Api. In my ASP.Net Web Api I have implemented following OWIN configuration in Startup class to validate the request JWT Bearer token issued by Auth0 as instructed here.

Statup:

 public class Startup
{
    public void Configuration(IAppBuilder app)
    {

        var auth0Options = new Auth0Options()
        {
            Issuer = $"https://{ConfigurationManager.AppSettings["Auth0ApiInternalDomain"]}/",
            Audience = ConfigurationManager.AppSettings["Auth0ApiInternalAudience"],
            ClientId = ConfigurationManager.AppSettings["Auth0ApiInternalClientID"]
        };

        Auth0Config.Configure(app, auth0Options);

        // Configure Web API
        WebApiConfig.Configure(app);
    }
}

and Auth0Config class:

public class Auth0Config
{
    public static void Configure(IAppBuilder app, Auth0Options options)
    {
        if (options == null)
            throw new ArgumentNullException(nameof(options));

        var keyResolver = new OpenIdConnectSigningKeyResolver(options.Issuer);

        app.UseJwtBearerAuthentication(
            new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidAudience = options.Audience,
                    ValidIssuer = options.Issuer,
                    IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => keyResolver.GetSigningKey(identifier),
                    ValidateLifetime = true,
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) =>
                    {
                        if (expires.Value < DateTime.UtcNow)
                        {
                            return false;
                        }
                        return true;
                    }
                }
            });
    }
}

I pass Audience, Issuer and CliedntId from my app.config to this method. My intention is to figure out whether the Bearer token coming from the client to my Api is valid or not (here as first step I need to validate expiration date). When I debug my code for the incoming request, LifetimeValidator works fine and returns false for the expired token. I decorated my action with [Authorize] and expected to get 401 error but the actual response is 200 and it seems it ignores the LifetimeValidator implementation.

My action:

[Authorize]
public IHttpActionResult Get(string id)
{
    var result = _bookingService.GetBooking(id);
    if (result == null) return NotFound();
    return Ok(result);
}
  1. Am I missing something to get it right?
  2. Is this a good approach to validate token expiration?
  3. Is it possible to use OWIN only to validate the request Bearer token that has been issued out of web api application?

Solution

    1. It turned out Invoke method of OwinMiddleware class had been overridden in my application to find Username from token and inject it to Request.User. Not sure why but somehow it ignores OWIN token validation functionality and didn't check Audience, Issuer or Expiration time.

      public static void Configure(IAppBuilder app)
      {
          HttpConfiguration config = new HttpConfiguration();
          app.Use<HttpUsernameInjector>();
          app.UseWebApi(config);
      }
      
      public class HttpUsernameInjector : OwinMiddleware
      {
        public HttpUsernameInjector(OwinMiddleware next)
          : base(next){}
      
        public override async Task Invoke(IOwinContext context)
        {
          const string usernameClaimKey = "myUserNameClaimKey";
      
          var bearerString = context.Request.Headers["Authorization"];
          if (bearerString != null && bearerString.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
          {
              var tokenString = bearerString.Substring(7);
      
              var token = new JwtSecurityToken(tokenString);
              var claims = token.Claims.ToList();
              var username = claims.FirstOrDefault(x => x.Type == usernameClaimKey);
      
              if (username == null) throw new Exception("Token should have username");
      
              // Add to HttpContext
              var genericPrincipal = new GenericPrincipal(new GenericIdentity(username.Value), new string[] { });
      
              IPrincipal principal = genericPrincipal;
      
              context.Request.User = principal;
          }
      
          await Next.Invoke(context);
        }
      }
      

    by removing this class, OWIN token validation works fine!

    1. Base on my research, the best token validation approaches in Web Api are OWIN and also IAuthenticationFilter.
    2. It is possible as Resource Server and Authorization Server are decoupled. More info can be found here

    Update

    Found the solution here to stop OwinMiddleware suppressing my token validation logic