Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication Swagger with JWT Bearer token

We are developing a .Net Core 2.1 Web API with JWT Bearer authentication. The application itself will generate and hand out tokens which are to be send to the backend.

While we have everything up and running, i.e. we can send the bearer token from Angular and test it with Postman, Swagger won't send the Bearer token. We have added the Swagger configuration to use a SecurityDefinition as followed, I will post the complete ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddMvc();
        services.AddCors(options =>
        {
            options.AddPolicy("AllowAllOrigins",
                policy => policy.WithOrigins("*").AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
        });
        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new CorsAuthorizationFilterFactory("AllowAllOrigins"));
        });

        ServiceInstaller.Install(services, Configuration);

        // api user claim policy
        services.AddAuthorization(options =>
        {
            var authorizationPolicy = new AuthorizationPolicyBuilder()
                .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                .RequireAuthenticatedUser().Build();
            options.AddPolicy("Bearer", authorizationPolicy);
        });
        // add identity
        var builder = services.AddIdentityCore<AppUser>(o =>
        {
            // configure identity options
            o.Password.RequireDigit = false;
            o.Password.RequireLowercase = false;
            o.Password.RequireUppercase = false;
            o.Password.RequireNonAlphanumeric = false;
            o.Password.RequiredLength = 6;
        });
        builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole), builder.Services);
        builder.AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

        var keyByteArray = Encoding.ASCII.GetBytes("placekeyhere");
        var signingKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(keyByteArray);
        services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(
            options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    IssuerSigningKey = signingKey,
                    ValidAudience = "Audience",
                    ValidIssuer = "Issuer",
                    ValidateIssuerSigningKey = true,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.FromMinutes(0)
                };
            });
        // Configure JwtIssuerOptions
        services.Configure<JwtIssuerOptions>(options =>
        {
            options.Issuer = "Issuer";
            options.Audience = "Audience";
            options.SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
        });

        // Register the Swagger generator, defining one or more Swagger documents
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info { Title = "AppName", Version = "v1" });
            c.OperationFilter<UploadOperation>();
            c.AddSecurityDefinition("Authorization", new ApiKeyScheme
            {
                Description =
                    "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = "header",
                Type = "apiKey",
            });
        });
    }

This does add the Authenticate option to the top of the screen. In the configure method we tell the application to actually use the authentication:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseAuthentication();
        if (env.IsDevelopment())
        {
            // Enable middleware to serve generated Swagger as a JSON endpoint.
            app.UseCors();
            app.UseSwagger();
            // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
            app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "AppName"); });
        }
        app.UseMvc();
    }

However when we authenticate ourselves with a token, the curl for the function does not show the Bearer token. It looks like Swagger does not send the token to the backend.

We use .Net Core 2.1 and Swagger 2.3. Any help would be appreciated, thank you.

like image 857
Edwin Avatar asked Mar 20 '18 09:03

Edwin


1 Answers

Update - The Swagger spec has changed. check answer by @nilay below for the correct solution.

I had the very same problem.

2 things are neccessary

  1. You have to put "bearer <token-here>" like this. Putting only token will not work.

to get this to work in swagger 2.x, you need to accompany your scheme definition with a corresponding requirement to indicate that the scheme is applicable to all operations in your API:

c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
{
    { "Bearer", new string[] { } }
});

Complete definition:

services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info { Title = "Some API", Version = "v1" });
                c.AddSecurityDefinition("Bearer", new ApiKeyScheme()
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = "header",
                    Type = "apiKey"
                });
                c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
                {
                    { "Bearer", new string[] { } }
                });
            });
like image 149
Radim Drtílek Avatar answered Sep 21 '22 00:09

Radim Drtílek