The Story of My Life

Diary of a noob programmer

Swagger and Authentication in ASP.NET MVC Core

Hello people,

 

Few day ago my co-worker said how should I specify token for user, well the story goes as:

When I enter this company (“Omidan Hozoor Javan”) they used a GUID as a token, and when i explained that it’s not safe, they said our users have no understanding of programming or hacking and that suffice… So it take me long, but a month ago, I could affect their way of thinking, and then I implement it and show the project master how easily it can be achieved.

So, to the team it was new and they never used headers before. then she explained that the swagger doesn’t specify the model, so I wen’t to the swagger platform page, to point out when it shows such header… and there was none.

So I searched for sometime and fixed the issue in my swagger configuration as following:

Note: If you are not have access to these classes, you may either using an older version of the package, or you are using something came later than the one I wrote here.

public class Startup
{
    ...
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSwaggerGen(c =>
        {
            ...
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n 
                  Enter 'Bearer' [space] and then your token in the text input below.
                  \r\n\r\nExample: 'Bearer 12345abcdef'",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey,
                Scheme = "Bearer"
            });

            c.AddSecurityRequirement(new OpenApiSecurityRequirement()
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        },
                        Scheme = "oauth2",
                        Name = "Bearer",
                        In = ParameterLocation.Header,

                    },
                    new List<string>()
                }
            });
            ...
        });
        ...
    }
    ...
}

This will add a global and a service specific, ‘lock’ sign, to your swagger page. And you can explain to your user that they need to specify the authentication token, and also the type that their token is based on. you can also have two or more security definition depending on your needs:

c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
    Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n 
      Enter 'Bearer' [space] and then your token in the text input below.
      \r\n\r\nExample: 'Bearer 12345abcdef'",
    Name = "Authorization",
    In = ParameterLocation.Header,
    Type = SecuritySchemeType.ApiKey,
    Scheme = "Bearer"
});
c.AddSecurityDefinition("Basic", new OpenApiSecurityScheme
{
    Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n 
      Enter 'Bearer' [space] and then your token in the text input below.
      \r\n\r\nExample: 'Basic 12345abcdef'",
    Name = "Authorization",
    In = ParameterLocation.Header,
    Type = SecuritySchemeType.ApiKey,
    Scheme = "Basic"
});
c.AddSecurityDefinition("Query", new OpenApiSecurityScheme
{
    Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n 
      Enter 'Bearer' [space] and then your token in the text input below.
      \r\n\r\nExample: '?AuthToken=12345abcdef'",
    Name = "AuthToken",
    In = ParameterLocation.Query,
    Type = SecuritySchemeType.ApiKey,
    Scheme = "Query"
});

c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
    {
        new OpenApiSecurityScheme
        {
            Reference = new OpenApiReference
            {
                Type = ReferenceType.SecurityScheme,
                Id = "Bearer"
            },
            Scheme = "oauth2",
            Name = "Bearer",
            In = ParameterLocation.Header,

        },
        new List<string>()
    }
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
    {
        new OpenApiSecurityScheme
        {
            Reference = new OpenApiReference
            {
                Type = ReferenceType.SecurityScheme,
                Id = "Basic"
            }
        },
        new List<string>()
    }
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
    {
        new OpenApiSecurityScheme
        {
            Reference = new OpenApiReference
            {
                Type = ReferenceType.SecurityScheme,
                Id = "Query"
            },
            Name="Query",
            In = ParameterLocation.Query
        },
        new List<string>()
    }
});

Note, that for basic and query, I’m not fully aware of the configuration.

The code I wrote are based on “Swashbuckle” swagger package provided for .NET Core.

For those of you who are new to this package, I’ll write my “Startup.cs” configuration in case you need it:

First install this package:

Swashbuckle.AspNetCore (Mine is version 5.1)
PM> Install-Package Swashbuckle.AspNetCore -Version 5.1.0
Startup.cs
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System.Collections.Generic;

using Microsoft.OpenApi.Models;
using System.Reflection;
using System.IO;


namespace <Your Project Namespace>
{
    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)
        {
            ...

            // HERE lies my configuration for JWT token, which may be far different for you
            //
            // configure strongly typed settings objects
            //var appSettingsSection = Configuration.GetSection("AppSettings");
            //services.Configure<AppSettings>(appSettingsSection);
            //
            // BEGIN configure jwt authentication
            //var appSettings = appSettingsSection.Get<AppSettings>();
            //var key = Encoding.ASCII.GetBytes(appSettings.JwtSecret);
            //services.AddAuthentication(x =>
            //    {
            //        x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            //       x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            //    })
            //    .AddJwtBearer(x =>
            //    {
            //        x.RequireHttpsMetadata = false;
            //        x.SaveToken = true;
            //        x.TokenValidationParameters = new TokenValidationParameters
            //        {
            //            ValidateIssuerSigningKey = true,
            //            IssuerSigningKey = new SymmetricSecurityKey(key),
            //            ValidateIssuer = false,
            //            ValidateAudience = false
            //        };
            //    });
            // END configure jwt authentication

            // Most of the Swagger configuration goes here:
            services.AddSwaggerGen(c =>
            {
                // Swagger configuration about your API
                c.SwaggerDoc("v1", new OpenApiInfo {Title = "[Your project title] Documentations", Version = "v1"});

                // This one and the next one are for adding authentication to the Swagger UI (Configured for Bearer token)
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = @"JWT Authorization header using the Bearer scheme. \r\n\r\n 
                      Enter 'Bearer' [space] and then your token in the text input below.
                      \r\n\r\nExample: 'Bearer 12345abcdef'",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    Scheme = "Bearer"
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            },
                            Scheme = "oauth2",
                            Name = "Bearer",
                            In = ParameterLocation.Header,

                        },
                        new List<string>()
                    }
                });


                // Set the comments path for the Swagger JSON and UI. (Only if you are using XML Documentation File to describe your project, and somehow depend on the configuration, you need to have at least one section in your code, otherwise the compiler will ignore it. 
                // you need to tell your project to build the DLL xml documentation file. Otherwise you will get 500 Internal Server Error)
                // Can be activated in: Right click on web project -> Properties -> Build Tab -> Output section (at the bottom of the Build Tab) -> Check the "XML Documentation File:" and use this path: "./<ProjectName|outputDLL-Name>.xml" -> Close & Save
                var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
        {
            ...

            // This configuration is to route the Swagger web view. and it will be <Domain Root or LocalHost>/swagger
            app.UseSwagger();
            // This configuration is consuming the swagger service descriptor, which is an API, outputing metadata of your service. So the UI can use it to show your project services.
            app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); });
        }
    }

}

And done.

 

Thank you for your time,
Hassan F.

Leave a Reply

Your email address will not be published. Required fields are marked *.

*
*
You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>