locked
How to return a custom json error schema from asp.net WebApi when using JwtBearerAuthentication RRS feed

  • Question

  • User-1090655690 posted

    I have an asp.net WebAPI project to provide REST services, where I use the following packages to both create and consume JWT tokens for Bearer authentication/authorization..

    <package id="Microsoft.Owin.Security" version="4.0.0" targetFramework="net47" />
    <package id="Microsoft.Owin.Security.Jwt" version="3.1.0" targetFramework="net47" />
    <package id="Microsoft.Owin.Security.OAuth" version="4.0.0" targetFramework="net47" />
    

    I configure it up as follows..

    OAuthAuthorizationServerOptions oauthServerOptions = new OAuthAuthorizationServerOptions()
    		  {
    			AllowInsecureHttp = true,
    			TokenEndpointPath = new PathString(TokenEndPoint),
    			AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(config.SecuritySettings.AccessTokenExpiryMins ?? 1),
    			Provider = new AuthorisationServerProvider(servicesFacade, securityDataRepository, resourceProvider, m_logger),
    			AccessTokenFormat = new CustomJwtFormat(config, resourceProvider, m_logger),
    			RefreshTokenProvider = new RefreshTokenProvider(securityDataRepository, config.SecuritySettings, m_logger),
    		
    		  };
    
    		  app.UseOAuthAuthorizationServer(oauthServerOptions);
    
    		  OAuthBearerAuthenticationOptions bearerOptions = new OAuthBearerAuthenticationOptions
    		  {
    			AccessTokenFormat = oauthServerOptions.AccessTokenFormat,
    			AccessTokenProvider = oauthServerOptions.AccessTokenProvider,
    			AuthenticationMode = oauthServerOptions.AuthenticationMode,
    			AuthenticationType = oauthServerOptions.AuthenticationType,
    			Description = oauthServerOptions.Description,
    			SystemClock = oauthServerOptions.SystemClock
    		  };
    		  
    		  app.UseOAuthBearerAuthentication(bearerOptions);
    
    		 var issuer = config.SecuritySettings.AudienceId;
    		  byte[] audienceSecret = System.Text.Encoding.Unicode.GetBytes(config.SecuritySettings.AudienceSecret);
    
    		  // API controllers with an [Authorize] attribute will be validated with JWT
    		
    		  app.UseJwtBearerAuthentication(
    			new JwtBearerAuthenticationOptions
    			{
    			  AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
    			  AllowedAudiences = new[] {config.SecuritySettings.AudienceId},
    			  IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
    			  {
    				new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
    			  },
    			
    			});
    

    In the `CustomJwtFormat` I have override the `Protect` and `Unprotect` methods.

    The Unprotect method is implemented as follows..

    public AuthenticationTicket Unprotect(string protectedText)
    			{
    			  var handler = new JwtSecurityTokenHandler();
    			  ClaimsPrincipal principal;
    
    			  try
    			  {
    				SecurityToken validToken;
    				principal = handler.ValidateToken(protectedText, m_tokenValidationParameters, out validToken);
    				var validJwt = validToken as JwtSecurityToken;
    				if (validJwt == null)        
    				  throw new ArgumentException(m_resourceProvider.GetInvalidJwtError().ToString());
    
    				if (!validJwt.Header.Alg.Equals(SigningAlgorithm, StringComparison.Ordinal))
    				  throw new ArgumentException(m_resourceProvider.GetInvalidJwtAlgorithmError().ToString());
    
    				// Additional custom validation of JWT claims here (if any)
    			  }
    			  catch (SecurityTokenValidationException ex)
    			  {
    				m_logger.WriteInformation(ex.ToString());
    				return null;
    			  }
    			  catch (ArgumentException aex)
    			  {
    				m_logger.WriteError(aex.ToString());
    				return null;
    			  }
    
    			  // Validation passed. Return a valid AuthenticationTicket:
    			  return new AuthenticationTicket(principal.Identities.FirstOrDefault(), new AuthenticationProperties());
    			}  
    		  }

    What I would like to do, is when the Unprotect fails (eg a token is no longer valid), I would like to provide my own json schema for the error returned, to match the rest of my application, rather than what the library supplies.

    I have tried everything I can think of (ExceptionFilters, Handlers etc), but just cannot see how to do this.

    Is there a way to do this, and if so how?

    Thanks in advance for any help.

    Monday, January 14, 2019 5:29 AM

All replies

  • User36583972 posted


    Hi peterjc2007,

    What I would like to do, is when the Unprotect fails (eg a token is no longer valid), I would like to provide my own json schema for the error returned, to match the rest of my application, rather than what the library supplies.

    I have tried everything I can think of (ExceptionFilters, Handlers etc), but just cannot see how to do this.

    Is there a way to do this, and if so how?

    You can refer the following article which created a filter for authentication which will be executed before every request. It will verify the token contained in the request header and will deny/allow resource based on token. Filter will does all the work related to decrypting, encrypting, signing & verifying the token.

    For more detailed: JSON Web Token (JWT) with Web API

    When incorrect token in the header. The method ShowAuthenticationError which is called through OnAuthorize method is described below:

        private static void ShowAuthenticationError(HttpActionContext filterContext)
            {
                var responseDTO = new ResponseDTO() { Code = 401, Message = "your  json schema" };
                filterContext.Response =
                filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized, responseDTO);
            }


    The following links may helpful for you.

    JSON Web Token in ASP.NET Web API 2 using Owin
    http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/

    bcgrillo/JWTAspNetWebApi
    https://github.com/bcgrillo/JWTAspNetWebApi/commit/d10b4018d472bb7cb35bb20c658697e653d0ad56

    Note: This response contains a reference to a third party World Wide Web site. Microsoft is providing this information as a convenience to you. Microsoft does not control these sites and has not tested any software or information found on these sites; therefore, Microsoft cannot make any representations regarding the quality, safety, or suitability of any software or information found there. There are inherent dangers in the use of any software found on the Internet, and Microsoft cautions you to make sure that you completely understand the risk before retrieving any software from the Internet.


    Best Regards,

    Yong Lu

    Tuesday, January 15, 2019 5:06 AM
  • User-1090655690 posted

    Thankyou Yong, 

    I will examine the above a bit closer. I can see the first link. you call the auth code manually from the controller. The second link (the Owin) looks similar to what I followed. The problems with the Owin way is you call the `context.SetError()` for any errors but don't seem to have any control over the shape of the json error returned (which is terrible).

    The Owin libs just look too "black box", so perhaps I need to switch to the first method, but that would means redoing everything. I was hoping the Owin way had some way to format these json objects, but so far, amazingly there just seems to be no way?

    Wednesday, January 16, 2019 1:35 AM
  • User36583972 posted

    Hi peterjc2007

    . I was hoping the Owin way had some way to format these json objects, but so far, amazingly there just seems to be no way?

    Unfortunately, after search some information. I have not found any articles about this and a suitable way to do this.

    Best Regards,

    Yong Lu

    Wednesday, January 16, 2019 5:41 AM