45

I searched for possible ways to add a request header parameter that would be added automatically to every method in my web-api but i couldn't find a clear one.

While searching i found that the method OperationFilter() has to do something about it.

  • Would love to know if this can be done via the Swagger UI? – IbrarMumtaz Jan 04 '19 at 13:52
  • [Follow this link. I have given answer there and it is working](https://stackoverflow.com/questions/59181467/how-to-implement-api-versioning-and-swagger-document-dynamically/59182213#59182213) – Dalip Choudhary Dec 04 '19 at 18:07

9 Answers9

87

What the user "G T" wrote is correct but it is not working with Swagger 5. We have some new changes:

From: Operation to: OpenApiOperation

From: IParameter to: OpenApiParameter

From: NonBodyParameter to: OpenApiParameter, and the most important is...

From: Type = "string" to: Schema = new OpenApiSchema { Type = "String" }

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace MyAPI
{
    public class AuthorizationHeaderParameterOperationFilter: IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var filterPipeline = context.ApiDescription.ActionDescriptor.FilterDescriptors;
            var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is AuthorizeFilter);
            var allowAnonymous = filterPipeline.Select(filterInfo => filterInfo.Filter).Any(filter => filter is IAllowAnonymousFilter);

            if (isAuthorized && !allowAnonymous)
            {
                if (operation.Parameters == null)
                    operation.Parameters = new List<OpenApiParameter>();

                operation.Parameters.Add(new OpenApiParameter 
                {
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Description = "access token",
                    Required = true,
                    Schema = new OpenApiSchema
                    {
                        Type = "string",
                        Default = new OpenApiString("Bearer ")
                    }
                });
            }
        }
    }
}

And in Startup => ConfigureServices => services.AddSwaggerGen()

c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
ladenedge
  • 12,165
  • 10
  • 56
  • 106
Wille Esteche
  • 1,039
  • 7
  • 6
  • 4
    Thx it works, but I had to make the parameter optional (Required=false) in 5.0.0-rc2) - otherwise i could not try it out (looks like it's a swashbucjke bug). – zerox981 Aug 29 '19 at 08:01
  • 1
    @wille-esteche I did it exactly like that, but it doesn't work. It used to work on the older version, where it was done like in the accepted answer. When I do Required true, the UI fails with a validation error, with required false the authorization header is never sent. – CodeHacker Oct 08 '19 at 08:59
  • @CodeHacker Think about to put the Authorization for each method and not only for all the controller. With Swagger 4 I used Authorization for the controller but now it is working if a put it on each method. Try it if it's your case! – Wille Esteche Oct 10 '19 at 20:08
  • @CodeHacker Did you ever get this working? Im having the same issue. – Chris Kooken Nov 01 '19 at 16:53
  • 1
    Answer to https://stackoverflow.com/questions/58179180/jwt-authentication-and-swagger-with-net-core-3-0 works! But don't forget to add "Bearer " before your actual token – CodeHacker Nov 08 '19 at 16:27
  • It works fine in Swashbuckle.AspNetCore 5.1.0. Thanks – capcom923 Mar 13 '20 at 10:47
  • Just to add that my controller actions were using the AuthorizeAttribute and the above code didn't work as isAuthorized was always false. I added in a check for this as well and it worked: var hasAuthorizeAttribute = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || context.MethodInfo.GetCustomAttributes(true).OfType().Any(); – John Mc Sep 15 '20 at 09:22
  • 4
    changing `Type = "String"` to `"Type = "string"` let's SwaggerUI work again with the `required = true` attribute! – Adam Oct 16 '20 at 07:36
62

Yes you can do it via inheriting from IOperationFilter

You can find the answer on GitHub here: AddRequiredHeaderParameter

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;

public class AddRequiredHeaderParameter : IOperationFilter
{
    public void Apply(Operation operation, OperationFilterContext context)
    {
        if (operation.Parameters == null)
            operation.Parameters = new List<IParameter>();

        operation.Parameters.Add(new NonBodyParameter
            {
                Name = "X-User-Token",
                In = "header",
                Type = "string",
                Required = false
            });
    }
}

Then you go to your SwaggerConfig.cs file and add the following in the AddSwaggerGen section:

c.OperationFilter<AddRequiredHeaderParameter>();

Rebuild, and enjoy.

Ian Kemp
  • 24,155
  • 16
  • 97
  • 121
Ramy M. Mousa
  • 4,656
  • 3
  • 32
  • 40
  • @SoftwareEngineer It seems that the problem is in the ` AddRequiredHeaderParameter ` class trying to inherit from ` IOperationFilter ` make sure you installed swagger and referenced it to your project. – Ramy M. Mousa Oct 31 '17 at 09:47
  • @Saveen I'm not sure If I understand what you mean, but this code will add the same parameter to all the APIs you have. if doesn't cancel your function parameters, it only adds this one with the others associated with each API function. – Ramy M. Mousa Mar 27 '18 at 18:10
  • @RamyMohamed I Have found the solution to add parameter in specific action method by a little modification in above code. Thanks for providing the reference code above. – Saveen Mar 28 '18 at 04:54
  • @RamyMohamed Any idea why we check if operation.Parameters is null? What is the use case that this becomes null? – Zein Sleiman Oct 28 '19 at 16:35
  • @ZeinSleiman it becomes null when a service has zero path or query string parameters. – Ramy M. Mousa Oct 28 '19 at 20:11
  • @RamyMohamed When you say or query string parameters, do you mean no parameters passed or only query parameters passed. Also thanks for replying. – Zein Sleiman Oct 29 '19 at 17:32
  • @Saveen can you share the piece of code that used the header for specific action – Prasad Raja Dec 09 '20 at 19:03
35

Another way to add custom headers is by adding parameters into controller action.
The following example will add x-test parameter to the UI:

[HttpPost]
public IActionResult Test([FromHeader(Name="x-test")][Required] string requiredHeader)
{
    return Ok();
}

enter image description here

Pavel Agarkov
  • 3,005
  • 17
  • 16
7

For Asp .Net MVC 5 you can use.
Following the need to be done in Swagger Config file.

private class AddAuthorizationHeaderParameter: IOperationFilter   // as a nested class in script config file.
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
            operation.parameters = new List<Parameter>();

        operation.parameters.Add(new Parameter
        {
            name = "Authorization",
            @in = "header",
            type = "string",
            required = true
        });
    }
}

c.OperationFilter<AddAuthorizationHeaderParameter>(); // finally add this line in .EnableSwagger

You can also add any no of headers for header implementation in Swagger.

adiga
  • 28,937
  • 7
  • 45
  • 66
Rajat Nigam
  • 89
  • 1
  • 4
7

I have improved the respectful Wille Esteche's answer a bit. If you want to apply headers not to all methods, but only to your selected controller methods, you can use attributes.

    [HttpPost]
    [Route(nameof(Auth))]
    [SwaggerHeader(Constants.HeaderDomainSid, "Encrypted User.Sid got from client", "abc123", true)]
    public ActionResult<string> Auth([FromHeader(Name = Constants.HeaderDomainSid)] string headerDomainSid = null)
    { .....
    

Attribute class:

public class SwaggerHeaderAttribute : Attribute
{
    public string HeaderName { get; }
    public string Description { get; }
    public string DefaultValue { get; }
    public bool IsRequired { get; }

    public SwaggerHeaderAttribute(string headerName, string description = null, string defaultValue = null, bool isRequired = false)
    {
        HeaderName = headerName;
        Description = description;
        DefaultValue = defaultValue;
        IsRequired = isRequired;
    }
}

Filter:

public class SwaggerHeaderFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        operation.Parameters ??= new List<OpenApiParameter>();

        if (context.MethodInfo.GetCustomAttribute(typeof(SwaggerHeaderAttribute)) is SwaggerHeaderAttribute attribute)
        {
            var existingParam = operation.Parameters.FirstOrDefault(p =>
                p.In == ParameterLocation.Header && p.Name == attribute.HeaderName);
            if (existingParam != null) // remove description from [FromHeader] argument attribute
            {
                operation.Parameters.Remove(existingParam);
            }

            operation.Parameters.Add(new OpenApiParameter
            {
                Name = attribute.HeaderName,
                In = ParameterLocation.Header,
                Description = attribute.Description,
                Required = attribute.IsRequired,
                Schema = string.IsNullOrEmpty(attribute.DefaultValue)
                    ? null
                    : new OpenApiSchema
                    {
                        Type = "String",
                        Default = new OpenApiString(attribute.DefaultValue)
                    }
            });
        }
    }
}
    

enter image description here

Gennady Maltsev
  • 111
  • 1
  • 3
3

If swagger is used in ASP.Net MVC5, and required to add headers to get input from swagger UI.

Create a class inherited from IOperationFilter:

using Swashbuckle.Swagger;
using System.Collections.Generic;
using System.Web.Http.Description;

public class AddHeaderParameters : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        if (operation.parameters == null)
            operation.parameters = new List<Parameter>();

        operation.parameters.Add(new Parameter
        {
            name = "AccountUserName",
            @in = "header",
            type = "string",
            required = true,
            //description = "Account username"
        });    
    }
}

Give reference of this class in SwaggerConfig.cs inside Configuration.EnableSwagger as:

c.OperationFilter<AddHeaderParameters>();

Important thing to note that the header name supposed to match with the actual header you have created for API.

Sh.Imran
  • 996
  • 6
  • 13
2

Also you may have a base model class and use attribute [FromHeader] for properties which should be sent in custom headers. Something like this:

public class AuthenticatedRequest
{
    [FromHeader(Name = "User-Identity")]
    public string UserIdentity { get; set; }
}

At least it works fine for ASP.NET Core 2.1 and Swashbuckle.AspNetCore 2.5.0.

  • ASP.Net Core 3 and Swashbuckle.AspNetCore 5.0.0-rc4 does not seem to work. The generated documentation puts the entire class as the request body. – Jeremy Dec 02 '19 at 17:26
1

In my case (.NET 5) I have to change some :

using System.Collections.Generic;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

public class AddRequiredHeaderParameter : IOperationFilter
{
     public void Apply(OpenApiOperation operation, OperationFilterContext context)
     {
         if (operation.Parameters == null)
             operation.Parameters = new List<OpenApiParameter>();

         operation.Parameters.Add(new OpenApiParameter()
         {
             Name = "userNr",
             In = ParameterLocation.Header,
             Required = true
         });

         operation.Parameters.Add(new OpenApiParameter()
         {
             Name = "periodNo",
             In = ParameterLocation.Header,
             Required = true
         });
     }
 }

and in Startup.cs --> ConfigureServices --> AddSwaggerGen add

c.OperationFilter<AddRequiredHeaderParameter>();
Ramil Aliyev
  • 2,142
  • 1
  • 15
  • 26
1

This works for Swashbucke.AspNetCore 5.6.3

Create a new file and add the code below to the file

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace YourNameSpace
{
    public class AuthorizationHeaderParameterOperationFilter:IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            if (operation.Security == null)
                operation.Security = new List<OpenApiSecurityRequirement>();


            var scheme = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" } };
            operation.Security.Add(new OpenApiSecurityRequirement
            {
                [scheme] = new List<string>()
            });
        
        }
    }
}

In your Startup.cs add the code below to the ConfigureServices under services.AddSwaggerGen()

c.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
{
    Type = SecuritySchemeType.Http,
    BearerFormat = "JWT",
    In = ParameterLocation.Header,
    Scheme = "bearer"
});
c.OperationFilter<AuthorizationHeaderParameterOperationFilter>();

All should work fine now for more information check here