locked
Return custom json response when Unauthorized / token expired RRS feed

  • Question

  • User381809404 posted

    Hi,

    I have implemented one .net core API project where i am using JWT for token authorization and it works fine in case of correct token but if token is expired or Unauthorized access, it gives status code inside POSTMAN but i wanted to return json response in POSTMAN body to show custom json on my api call result.

    You can check my source code.

    Startup.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using Microsoft.IdentityModel.Tokens;
    
    namespace TestJWT
    {
        public class Startup
        {
            public Startup(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            public IConfiguration Configuration { get; }
    
            // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
                {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidIssuer = "mysite.com",
                        ValidateAudience = true,
                        ValidAudience = "mysite.com",
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("sdfoiweklmnjlk2#lkjadsfms.dcizdsdlkfjls@!1@dfsdf"))
                    };
                });
    
                services.AddMvc();
            }
    
            // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseAuthentication();
                app.UseMvc();
            }
        }
    }
    

    AuthController

    using System;
    using System.Collections.Generic;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.IdentityModel.Tokens;
    using System.Text;
    
    namespace TestJWT.Controllers
    {
        [Route("api/[controller]")]
        public class AuthController : Controller
        {
            [HttpPost("token")]
            public IActionResult Token()
            {
                string header = Request.Headers["Authorization"];
                if (header.StartsWith("Basic"))
                {
                    var credValue = header.Substring("Basic".Length).Trim();
                    var usernameAndPassenc = Encoding.UTF8.GetString(Convert.FromBase64String(credValue));
                    var userNameandPassword = usernameAndPassenc.Split(":");
    
                    if(userNameandPassword[0] == "Admin" && userNameandPassword[1] == "pswd")
                    {
                        //var claimsdata = new[] { new Claim(ClaimTypes.Name, "userName"), new Claim(ClaimTypes.Name, "userId") };
                        var claimsdata = new[] { new Claim(JwtRegisteredClaimNames.Sub, "Pritesh"), new Claim(JwtRegisteredClaimNames.Sub, "Mehta") };
    
                        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("sdfoiweklmnjlk2#lkjadsfms.dcizdsdlkfjls@!1@dfsdf"));
                        var signInCred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature);
    
                        var token = new JwtSecurityToken(
                            issuer: "mysite.com",
                            audience: "mysite.com",
                            expires: DateTime.Now.AddMinutes(1),
                            claims: claimsdata,
                            signingCredentials: signInCred
                        );
    
                        var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
    
                        return Ok(new {
                            token = tokenString,
                            id = userNameandPassword[1],
                            expires = token.ValidTo
                        });
                    }
                }
                return BadRequest("Wrong Request");
            }
        }
    }

    ValuesController

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    
    namespace TestJWT.Controllers
    {
        [Route("api/[controller]")]
        public class ValuesController : Controller
        {
            [Authorize]
            // GET api/values
            [HttpGet]
            public IEnumerable<string> Get()
            {
                return new string[] { "value1", "value2" };
            }
    
            // GET api/values/5
            [HttpGet("{id}")]
            public string Get(int id)
            {
                return "value";
            }
    
            // POST api/values
            [HttpPost]
            public void Post([FromBody]string value)
            {
            }
    
            // PUT api/values/5
            [HttpPut("{id}")]
            public void Put(int id, [FromBody]string value)
            {
            }
    
            // DELETE api/values/5
            [HttpDelete("{id}")]
            public void Delete(int id)
            {
            }
        }
    }
    

    Thank you.

    Monday, August 6, 2018 9:32 AM

All replies

  • User475983607 posted

    My best guess is you are asking how to return a custom 401 error?  For some reason a 401 is not good enough?

    Anyway, the ASP Core documentation explains how to handle custom error responses.

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-2.1

    You can format the response however you like.

    Monday, August 6, 2018 11:20 AM
  • User1634889493 posted

    Realize it has been a while since you asked this question, but maybe this will still help someone. Here is what I'm trying and it seems to work.

        public class ChallengeMiddleware
        {
            private static void writeErrorResponse(HttpContext Context, params string[] Errors)
            {
                Context.Response.ContentType = "application/json";
                using (var writer = new Utf8JsonWriter(Context.Response.BodyWriter))
                {
                    writer.WriteStartObject();
                    writer.WriteBoolean("isValid", false);
                    writer.WriteStartArray("errors");
    
                    foreach (var error in Errors)
                    {
                        writer.WriteStringValue(error);
                    }
    
                    writer.WriteEndArray();
                    writer.WriteEndObject();
                    writer.Flush();
                }
            }
    
            private readonly RequestDelegate _request;
    
            public ChallengeMiddleware(RequestDelegate RequestDelegate)
            {
                if (RequestDelegate == null)
                {
                    throw new ArgumentNullException(nameof(RequestDelegate)
                        , nameof(RequestDelegate) + " is required");
                }
    
                _request = RequestDelegate;
            }
    
            public async Task InvokeAsync(HttpContext Context)
            {
                if (Context == null)
                {
                    throw new ArgumentNullException(nameof(Context)
                        , nameof(Context) + " is required");
                }
    
                await _request(Context);
    
                if(Context.Response.StatusCode == 401)
                {
                    writeErrorResponse(Context, "Please log in");
                }
            }

    I'm injecting into the pipeline in the Configure method at this point:

                    .UseAuthentication()
                    .UseMiddleware<ChallengeMiddleware>()  <- custom middleware
                    .UseAuthorization()

    Sunday, July 12, 2020 2:38 AM