Search code examples
c#asp.net-core-mvcasp.net-core-6.0

How can I secure the views in ASP.NET Core 6 MVC app with external jwt authentication


I am new to ASP.NET Core 6 MVC and I'm working on a small project where users can:

  1. Sign In (form is sent to an external API which returns a JWT token)
  2. View pages but only after authentication. The pages are data driven which will be fetched from external API using the JWT token.

I have tried to find answers but have not been able to get a clear answer. Can someone please point me in the right direction?


Solution

    1. First of all you will need the Microsoft.AspNetCore.Authentication.JwtBearer package

    2. In the Program.csfile (Depending if you want to use a Startup.cs or just go with the Program.cs as per default) you should Add the DefaultAuthenticateScheme and the DefaultChallengeScheme :

    The examples are without Startup.cs just for default Programm.cs from now on

    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.IdentityModel.Tokens;
    using System.IdentityModel.Tokens.Jwt;
    
    // Some Code
    
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }) 
    // Some Code
    
    1. then you need to configure the JWT Bearer token so chain the AddJwtBearer to the previous example and add authorizationwith AddAuthorization:
    builder.Services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }) // End of last snippet
        .AddJwtBearer(options =>
        {
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
                RequireExpirationTime = true,
                ClockSkew = TimeSpan.Zero,
            };
            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    if (context.Request.Query.ContainsKey("access_token"))
                    {
                        context.Token = context.Request.Query["access_token"];
                    }
    
                    return Task.CompletedTask;
                }
            };
        });
    builder.Services.AddAuthorization();
    
    1. Then you should specify the Authentication and Authorization Middleware by using :
    // Program.cs
    // after the old code snippet
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    
    app.UseAuthentication(); //Add this
    app.UseAuthorization(); //Add this
    
    app.Run();
    
    

    If you want to use Minimal API the full example could look like this:

    var builder = WebApplication.CreateBuilder(args);
    
    builder.Logging.ClearProviders();
    builder.Logging.AddConsole();
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    
    var key = Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]);
    builder.Services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
        {
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false,
                ValidateLifetime = true,
                RequireExpirationTime = true,
                ClockSkew = TimeSpan.Zero,
            };
            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = context =>
                {
                    if (context.Request.Query.ContainsKey("access_token"))
                    {
                        context.Token = context.Request.Query["access_token"];
                    }
    
                    return Task.CompletedTask;
                }
            };
        });
    builder.Services.AddAuthorization();
    
    builder.Services.AddCapDashboardStandalone();
    
    var app = builder.Build();
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.MapGet("/",  () => Results.LocalRedirect("/index.html", true));
    
    app.MapPost("/security/createToken",
        [AllowAnonymous](User user) =>
        {
            if (user is { UserName: "bob", Password: "bob" })
            {
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = new ClaimsIdentity(new[]
                    {
                        new Claim("Id", Guid.NewGuid().ToString()),
                        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
                        new Claim(JwtRegisteredClaimNames.Email, user.UserName),
                        new Claim(JwtRegisteredClaimNames.Jti,
                            Guid.NewGuid().ToString())
                    }),
                    Expires = DateTime.UtcNow.AddMinutes(60),
                    Issuer = "Test",
                    Audience = "Test",
                    SigningCredentials = new SigningCredentials
                    (new SymmetricSecurityKey(key),
                        SecurityAlgorithms.HmacSha512Signature)
                };
                var tokenHandler = new JwtSecurityTokenHandler();
                var token = tokenHandler.CreateToken(tokenDescriptor);
                var stringToken = tokenHandler.WriteToken(token);
                return Results.Ok(stringToken);
            }
            return Results.Unauthorized();
        });
    
    app.UseAuthentication();
    app.UseAuthorization();
    
    app.Run();