Swashbuckle.aspnetcore: Empty authorization header on requests for Swashbuckle.AspNetCore

Created on 18 Apr 2018  ·  20Comments  ·  Source: domaindrivendev/Swashbuckle.AspNetCore

Currently having an issue with authorization headers in swashbuckle for .net core
The first line of code on every endpoint is:

string auth = Request.Headers["Authorization"];

When using postman, everything works smoothly, but when making a request from localhost/swagger, the header is empty
when a breakpoint is inserted, the header is a null value.
the body of the request is in tact and everything works properly when the authorization is removed from the endpoint

In my services.AddSwaggerGen I add the security definition:

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info
            {
                Version = "v1",
                Title = "Employee Navigator",
                Description = "Authorization Key: Z29vZEtleQ==",
            });
            c.AddSecurityDefinition("Bearer", new ApiKeyScheme
            {
                Name = "Authorization",
                In = "header",
                Type = "apiKey",
                Description = "Authorization Key: Z29vZEtleQ=="
            });

        });

I have updated each of the following to be sure I wasn't missing anything:
Swashbuckle.AspNetCore.Swagger
Swashbuckle.AspNetCore.SwaggerGen
Swashbuckle.AspNetCore.SwaggerUI

my csproj file contains:
`

<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="2.4.0" />

<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="2.4.0" />

<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUi" Version="2.4.0" />

<PackageReference Include="Swashbuckle.AspNetCore" Version="1.1.0" />`

Most helpful comment

Please explain how to do this in ASP.NET Core 2.2. I have the following code in my startup but the "Available operations" popup is still empty and I do not get the "Authorization" added to the request headers.

            // Add security definitions
            var securityScheme = new OpenApiSecurityScheme()
            {
                Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                BearerFormat = "JWT",
                Scheme = "bearer"
            };
            c.AddSecurityDefinition("Bearer", securityScheme);

            // Add security requirements globally.  If needs to be unique per operation then use IOperationFilter.
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securityScheme, new string[] { });
            c.AddSecurityRequirement(securityRequirement);

I have found the solution here:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/Startup.cs

c.AddSecurityRequirement( new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } } );

All 20 comments

You have to add a "securityrequirement", not just the definition.

On Wed, Apr 18, 2018 at 2:17 PM, Patrick Reese notifications@github.com
wrote:

Currently having an issue with authorization headers in swashbuckle for
.net core
The first line of code on every endpoint is:

string auth = Request.Headers["Authorization"];

When using postman, everything works smoothly, but when making a request
from localhost/swagger, the header is empty
when a breakpoint is inserted, the header is a null value.
the body of the request is in tact and everything works properly when the
authorization is removed from the endpoint

In my services.AddSwaggerGen I add the security definition:

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info
        {
            Version = "v1",
            Title = "Employee Navigator",
            Description = "Authorization Key: Z29vZEtleQ==",
        });
        c.AddSecurityDefinition("Bearer", new ApiKeyScheme
        {
            Name = "Authorization",
            In = "header",
            Type = "apiKey",
            Description = "Authorization Key: Z29vZEtleQ=="
        });

    });

I have updated each of the following to be sure I wasn't missing anything:
Swashbuckle.AspNetCore.Swagger
Swashbuckle.AspNetCore.SwaggerGen
Swashbuckle.AspNetCore.SwaggerUI

my csproj file contains:
`

`


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/696,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFIxOutAaOckPlqSjFXjtRIPI3aCJO4tks5tp593gaJpZM4TatTG
.

I thought that was my issue, so I added:
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> { { "Authorization", new[] { "readAccess", "writeAccess" } } });
but nothing changed

@preese13 - try it with an empty array ...

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

From the Swagger 2.0 Spec

Each name must correspond to a security scheme which is declared in the Security Definitions. If the security scheme is of type "oauth2", then the value is a list of scope names required for the execution. For other security scheme types, the array MUST be empty.

I had tried creating it with an empty array but I got the error message:

The best overloaded Add method 'Dictionary>.Add(string, IEnumerable)' for the collection initializer has some invalid arguments

which makes little to no sense (at least to me) I thought that the invalid argument might have been "Authorization" so I switched it out with "apikey" and "api_key" as I saw the latter example given in the swaggerdoc documentation here:

https://swagger.io/specification/#securityRequirementObject

being unable to initialize an empty array at all, I figured it was time to create an issue

Just a syntax error - the array type can’t be inferred if it’s empty. Try “new string[] {}”

Nope, after implementing the new syntax I recieved:

Exception has occurred: CLR/System.NullReferenceException
An exception of type 'System.NullReferenceException' occurred in mockAPI.dll but was not handled in user code: 'Object reference not set to an instance of an object.'

I think I probably should have pointed out that I recently updated all of the swashbuckle packages for the first time since december. everything had been working fine before that. I updated the packages upon revisiting the project. Previously I had not used a security requirement at all, but it was working fine. I have been messing around with adding a document filter to my startup.cs file
(sorry for not using the code-formater its being difficult)

public class SecurityRequirementsDocumentFilter : IDocumentFilter
{
public void Apply(SwaggerDocument document, DocumentFilterContext context)
{
document.Security = new List>>()
{
new Dictionary>()
{
{ "Bearer", new string[]{ } },
{ "Basic", new string[]{ } },
}
};
}
}

I was still having the same issue, but then I changed my security requirement from "Authorization" to "Bearer"
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> { { "Bearer", new string[] { } } });

and it works fine

FYI, there is no need to add a SecurityRequirementsDocumentFilter.

define the add security requirement as

c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>

inside of which you will define:

{ "Bearer", new string[] { } }

the security definition should be defined as

c.AddSecurityDefinition("Bearer", new ApiKeyScheme

inside of which I have:

                Name = "Authorization",

                In = "header",

                Type = "apiKey",

                Description = ""

Correct - you would only need to use the operation filter if you need to specify per-operation security requirements. If the scheme is applied globally, your suggestion is much more convenient

@preese13 could you please provide full code. I'm having same issue

@ngohungphuc
Hey sorry I took so long to get back to you, I haven't checked github in a few days.. If you still need it here is what I think you want

            c.AddSecurityDefinition("Bearer", new ApiKeyScheme
            {
                Name = "Authorization",
                In = "header",
                Type = "apiKey",
            });
            c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>>
            {
                { "Bearer", new string[] { } }
            });

Please explain how to do this in ASP.NET Core 2.2. I have the following code in my startup but the "Available operations" popup is still empty and I do not get the "Authorization" added to the request headers.

            // Add security definitions
            var securityScheme = new OpenApiSecurityScheme()
            {
                Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                BearerFormat = "JWT",
                Scheme = "bearer"
            };
            c.AddSecurityDefinition("Bearer", securityScheme);

            // Add security requirements globally.  If needs to be unique per operation then use IOperationFilter.
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securityScheme, new string[] { });
            c.AddSecurityRequirement(securityRequirement);

I'm also getting the same issue as @teamboyd. The curl statement does not have the relevant -H parameters. Please help.

Please explain how to do this in ASP.NET Core 2.2. I have the following code in my startup but the "Available operations" popup is still empty and I do not get the "Authorization" added to the request headers.

            // Add security definitions
            var securityScheme = new OpenApiSecurityScheme()
            {
                Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                BearerFormat = "JWT",
                Scheme = "bearer"
            };
            c.AddSecurityDefinition("Bearer", securityScheme);

            // Add security requirements globally.  If needs to be unique per operation then use IOperationFilter.
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securityScheme, new string[] { });
            c.AddSecurityRequirement(securityRequirement);

I have found the solution here:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/Startup.cs

c.AddSecurityRequirement( new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } } );

It works @magiak tks very much.

Please explain how to do this in ASP.NET Core 2.2. I have the following code in my startup but the "Available operations" popup is still empty and I do not get the "Authorization" added to the request headers.

            // Add security definitions
            var securityScheme = new OpenApiSecurityScheme()
            {
                Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                BearerFormat = "JWT",
                Scheme = "bearer"
            };
            c.AddSecurityDefinition("Bearer", securityScheme);

            // Add security requirements globally.  If needs to be unique per operation then use IOperationFilter.
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securityScheme, new string[] { });
            c.AddSecurityRequirement(securityRequirement);

I have found the solution here:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/Startup.cs

c.AddSecurityRequirement( new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } } );

This should be documented.

Adding Reference = new OpenApiReference {... property solved my problem:

services.AddSwaggerGen(c => {
    var securityScheme = new OpenApiSecurityScheme {
        Reference = new OpenApiReference {
            Type = ReferenceType.SecurityScheme,
            Id = "Bearer"
        },
        Description = "JWT Token gerekiyor!",
        In = ParameterLocation.Header, // Header içinde Bearer token key gelecek
        Name = "Authorization", // Header içindeki token'ın header key bilgisi> Authorization: Bearer xlaskdfjsdf...
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    };
    c.AddSecurityDefinition("Bearer", securityScheme);

    // Security Requirement
    c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
            { securityScheme, Array.Empty<string>() }
        });
});

image

Whole ConfigureServices and Configure methods:

public void ConfigureServices(IServiceCollection services) {
services.AddControllers();

    #region Api Versiyonlama
    services.AddApiVersioning(v => {
        v.ReportApiVersions = true;
        v.AssumeDefaultVersionWhenUnspecified = true;
        v.DefaultApiVersion = new ApiVersion(1, 0);
        /* Eğer versiyon bilgisi tarih olsun istersek: */
        //v.DefaultApiVersion = new ApiVersion(new DateTime(2016, 7, 1));

        /* Eğer header ile versiyon bilgisi göndermezsek 
            *   - ya URL Segment 
            *   - ya da Querystring 
            * olarak versiyon bilgisini geçirebileceğiz.
            * 
            * Eğer versiyon bilgisini HTTP Header içinde göndermek istersek
            * URL Segment içinde versiyon bilgisi alabilecek şekilde işaretlenmemiş
            * denetleyiciler yani Querystring ile çalışabilen denetleyiciler 
            * header'dan gelen versiyon bilgisine göre çalışabilir.
            * Çalışır  > [Route("api/versioning")]
            * ÇalışMAZ > [Route("api/v{version:apiVersion}/versioning")]
            * 
            * Header içinde versiyonu taşıyan key'in ne olacağını burada belirtebiliriz
            */
        v.ApiVersionReader = new HeaderApiVersionReader("verMEZsion");
    });
    #endregion

    #region Swagger 2.0 - OpenApi 3.0
    services.AddSwaggerGen(c => {

        /* new SwaggerDocument()
            * Tüm Controller sınıflarının versiyon bilgilerini topla 
            * ve her biri için SwaggerDocument yarat. Böylece açılır kutuda
            * her versiyon için detay bilgi toplayabil.
            */
        #region SwaggerDocument Nesnelerini Yarat
        foreach (var version in Versions) {
            var swaggerDocument = new OpenApiInfo {
                Version = version,
                Title = "API Şablonu",
                Description = "Örnek Web API swagger açıklaması",
                TermsOfService = new Uri("https://example.com/terms"),
                Contact = new OpenApiContact {
                    Name = "Shayne Boyer",
                    Email = string.Empty,
                    Url = new Uri("https://twitter.com/spboyer"),
                },
                License = new OpenApiLicense {
                    Name = "Use under LICX",
                    Url = new Uri("https://example.com/license"),
                }
            };
            c.SwaggerDoc(version, swaggerDocument);
        }
        #endregion

        /* SwaggerDocument <> Controller Eşleşmesi
            * Versiyon numaralarına göre oluşturulmuş SwaggerDocument nesnelerine
            * uygun düşecek Controller sınıflarını ekle. Bunun için: 
            * denetleyicilerin ApiVersionAttribute niteliklerine bak, 
            * eğer Controller'ın  versiyon numarasıyla, SwaggerDocument nesnesinin versiyon numarası aynıysa
            * ilgili SwaggerDocument içinde görüntülemek için dahil et.
            */
        #region SwaggerDocument nesneleriyle Controller tiplerini eşleştir.
        c.DocInclusionPredicate((docName, apiDesc) => {

            if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;

            var versions = methodInfo.DeclaringType // Api içinde tanımlı tipleri getir
                .GetCustomAttributes(true) // Niteliklerini çek
                .OfType<ApiVersionAttribute>() // ApiVersionAttribute tipindeki nitelikleri süz
                .SelectMany(attr => attr.Versions); // ApiVersion niteliğindeki Versions özelliklerini flat dön

            return versions.Any(v => v.ToString() == docName);
        });
        #endregion

        // Set the comments path for the Swagger JSON and UI.
        var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
        var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
        c.IncludeXmlComments(xmlPath);
    });
    #endregion

    #region Swagger için JSON Web Token Ayarları
    services.AddSwaggerGen(c => {
        var securityScheme = new OpenApiSecurityScheme {
            Reference = new OpenApiReference {
                Type = ReferenceType.SecurityScheme,
                Id = "Bearer"
            },
            Description = "JWT Token gerekiyor!",
            In = ParameterLocation.Header, // Header içinde Bearer token key gelecek
            Name = "Authorization", // Header içindeki token'ın header key bilgisi> Authorization: Bearer xlaskdfjsdf...
            Type = SecuritySchemeType.ApiKey,
            Scheme = "Bearer"
        };
        c.AddSecurityDefinition("Bearer", securityScheme);

        // Security Requirement
        c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
                { securityScheme, Array.Empty<string>() }
            });
    });
    #endregion

    #region JSON Web Token ayarları
    var jwtSettings = new TokenSettings();
    this.Configuration.Bind("jwtSettings", jwtSettings);

    services.AddAuthentication(opt => {
        /**
            * Bir Controller niteliğinde [Authorize] kullandığınızda, 
            * ilk yetkilendirme sistemine varsayılan olarak bağlaması için
            */
        opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

        /**
            * Eğer `services.AddIdentity>()` ile bir kimlik kullanıyorsanız, 
            * DefaultChallengeScheme sizi bir giriş sayfasına yönlendirmeye çalışacaktır, 
            * eğer bir kimlik mevcut değilse, 404 döner. Eğer var ve yetkisiz ise 401 "yetkisiz erişim" hatası alacaksınız.
            */
        opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(opt => {
        Microsoft.IdentityModel.Tokens.TokenValidationParameters param;

        param = new TokenValidationParameters {
            // Require Bilgileri yoksa geçersiz kıl!
            RequireSignedTokens = true,
            RequireExpirationTime = true,

            // Neleri doğrulamasını istiyorsak
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateIssuerSigningKey = true,
            ValidateLifetime = true,

            // Beklediğimiz Issuer ve Audience bilgilerini veririz
            ValidIssuer = jwtSettings.Issuer,
            ValidAudience = jwtSettings.Audience,

            /**
                * Gelen token bilgisiyle, gönderdiğimizin imzası aynı mı diye 
                * geleni imzalayacak ve kontrol edeceğiz
                */
            IssuerSigningKey = jwtSettings.IssuerSigningKey,
        };

        opt.RequireHttpsMetadata = false; // Production ortamı ise true yani https olsun diyebiliriz
        opt.SaveToken = true;
        opt.TokenValidationParameters = param;

        opt.Events = new JwtBearerEvents() {
            OnAuthenticationFailed = context => {
                context.Response.StatusCode = 401;
                context.Response.ContentType = "application/json; charset=utf-8";
                var message = context.Exception.ToString();
                var result = JsonConvert.SerializeObject(new { message });

                Console.WriteLine("HATA >>>> " + message);
                return context.Response.WriteAsync(result);
            }
        };
    });
    #endregion
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Error/Exception");

        app.UseStatusCodePagesWithReExecute("/Error/{0}");

        app.UseHsts();

        app.UseHttpsRedirection();
    }

    #region Swagger 
    // Enable middleware to serve generated Swagger as a JSON endpoint.
    app.UseSwagger();

    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c => {
        foreach (var v in Versions) {
            // Her versiyon için bir uç nokta yaratmasını Swagger'a söylüyoruz
            c.SwaggerEndpoint($"/swagger/{v}/swagger.json", $"API Şablonu v{v}");
        }
    });
    #endregion

    #region CORS - Cross Origin Resource Sharing Ayarları
    /* AllowAnyOrigin: Herhangi bir domain adından
        * AllowAnyMethod: Herhangi bir HTTP metoduyla (GET, POST, PATH vs)
        * AllowAnyHeader: Herhangi bir HTTP Header bilgisiyle 
        * Yani herkesle her durumda her şeyi paylaş
        */
    app.UseCors(confPolicy => {
        confPolicy.AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader();
    });
    #endregion

    app.UseRouting();

    #region JSON Web Token
    /* app.UseAuthorization() metodu app.UseRouting() ile app.UseEndpoints() arasında olmalı!
        * 
        * Configure your application startup by adding app.UseAuthorization() 
        * inside the call to Configure(..) in the application startup code. 
        * The call to app.UseAuthorization() must appear between app.UseRouting() and app.UseEndpoints(...)
        */
    app.UseAuthentication();
    app.UseAuthorization();
    #endregion

    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
}

For anyone looking for .NET Core 3.0 version... here's the code:

https://stackoverflow.com/a/58972781/114029

@magiak

Por favor, explique como fazer isso no ASP.NET Core 2.2. Eu tenho o seguinte código na minha inicialização, mas o pop-up "Operações disponíveis" ainda está vazio e não recebo a "Autorização" adicionada aos cabeçalhos da solicitação.

            // Add security definitions
            var securityScheme = new OpenApiSecurityScheme()
            {
                Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                BearerFormat = "JWT",
                Scheme = "bearer"
            };
            c.AddSecurityDefinition("Bearer", securityScheme);

            // Add security requirements globally.  If needs to be unique per operation then use IOperationFilter.
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securityScheme, new string[] { });
            c.AddSecurityRequirement(securityRequirement);

Encontrei a solução aqui:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/master/test/WebSites/OAuth2Integration/Startup.cs

c.AddSecurityRequirement( new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } } );

it worked for me, thank you very much

Not sure why mine doesn't work..

// Define the Api Key scheme that's in use (i.e. Implicit Flow)
                config.AddSecurityDefinition(ApiKeyAuthenticationOptions.DefaultScheme, new OpenApiSecurityScheme
                {
                    Description = "custom authorization header using the Api Key scheme. Example: \"{token}\"",
                    In = ParameterLocation.Header,
                    Name = ApiKeyAuthenticationOptions.HeaderKey,
                    Type = SecuritySchemeType.ApiKey,
                    Flows = new OpenApiOAuthFlows
                    {
                        Implicit = new OpenApiOAuthFlow
                        {
                            AuthorizationUrl = new Uri("/api/connect/validate", UriKind.Relative),
                            Scopes = new Dictionary<string, string>
                            {
                                { "readAccess", "Access read operations" },
                                { "writeAccess", "Access write operations" }
                            }
                        }
                    }
                });

                config.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme, 
                                Id = ApiKeyAuthenticationOptions.DefaultScheme
                            }
                        },
                        new[] { "readAccess", "writeAccess" }
                    }
                });

                // add Security information to each operation for OAuth2
                config.OperationFilter<SecurityRequirementsOperationFilter>();

And this class in case required:

public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
    {
        public const string DefaultScheme = "API Key";
        public string Scheme => DefaultScheme;
        public string AuthenticationType = DefaultScheme;
        public const string HeaderKey = "X-Api-Key";
    }

I met the same issue before and resolved it.

Now the available Authorization header works fine.

Please check my latest sample using SwashBuckle v5.5.1 and netcore 3.1
https://github.com/capcom923/MySwashBuckleSwaggerWithJwtToken

send-authorization-header

Was this page helpful?
0 / 5 - 0 ratings