Web Api How to add a Header parameter for all API in Swagger
Asked Answered
P

12

84

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.

Pollen answered 5/1, 2017 at 19:28 Comment(2)
Would love to know if this can be done via the Swagger UI?Illinium
Follow this link. I have given answer there and it is workingResponsive
E
90

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.

Enduring answered 5/1, 2017 at 19:35 Comment(8)
@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.Enduring
@Mascle 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.Enduring
@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.Mascle
@RamyMohamed Any idea why we check if operation.Parameters is null? What is the use case that this becomes null?Coastguardsman
@ZeinSleiman it becomes null when a service has zero path or query string parameters.Enduring
@RamyMohamed When you say or query string parameters, do you mean no parameters passed or only query parameters passed. Also thanks for replying.Coastguardsman
@Mascle can you share the piece of code that used the header for specific actionCorporate
I tried this. The customer header comes under Results View of httpContext.Request.Headers resultset but when I do var key = httpContext.Request.Headers.Where(z => z.Key == "CUSTOMKEY").FirstOrDefault(); I get key as [null,null]. Any ideas?Lemonade
L
138

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>();
Lexical answered 23/8, 2019 at 6:30 Comment(10)
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).Intemperate
@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.Wirehaired
@Wirehaired 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!Lexical
@Wirehaired Did you ever get this working? Im having the same issue.Oatmeal
Answer to #58179680 works! But don't forget to add "Bearer " before your actual tokenWirehaired
It works fine in Swashbuckle.AspNetCore 5.1.0. ThanksNonbelligerent
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<Microsoft.AspNetCore.Authorization.AuthorizeAttribute>().Any() || context.MethodInfo.GetCustomAttributes(true).OfType<Microsoft.AspNetCore.Authorization.AuthorizeAttribute>().Any();Quibbling
changing Type = "String" to "Type = "string" let's SwaggerUI work again with the required = true attribute!Monandrous
Just FYI, this example does not work with newer versions of Swashbuckle that are using Open API Spec 3 due to changes within the Swagger and how it handles auth. Basically behind the scenes it will remove the Authorization header if it finds it, see this article for more details: swagger.io/docs/specification/describing-parameters/…. The new suggested approach can be found in this article (look for domaindrivendev's response): github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1425Agma
This works well for me except that the check for the AllowAnonymous filter doesn't seem to work. Does anyone have any ideas?Unsex
E
90

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.

Enduring answered 5/1, 2017 at 19:35 Comment(8)
@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.Enduring
@Mascle 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.Enduring
@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.Mascle
@RamyMohamed Any idea why we check if operation.Parameters is null? What is the use case that this becomes null?Coastguardsman
@ZeinSleiman it becomes null when a service has zero path or query string parameters.Enduring
@RamyMohamed When you say or query string parameters, do you mean no parameters passed or only query parameters passed. Also thanks for replying.Coastguardsman
@Mascle can you share the piece of code that used the header for specific actionCorporate
I tried this. The customer header comes under Results View of httpContext.Request.Headers resultset but when I do var key = httpContext.Request.Headers.Where(z => z.Key == "CUSTOMKEY").FirstOrDefault(); I get key as [null,null]. Any ideas?Lemonade
B
66

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

Burch answered 23/3, 2019 at 19:51 Comment(3)
Just a quick note to say that the [FromHeader] attribute is only available for WebAPI instances which use ASP.Net Core, not full .Net.Burmese
Do we have anything like FromHeader in WebAPI 2.0 non .net core..?Downey
why isn't this the accepted answer? I guess I have a thing for really simple answers. Thanks, manEthelda
B
24

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

Bohrer answered 17/7, 2020 at 9:12 Comment(3)
This answer hit the spot for me. Ive done some custom attributes for controller methods that would read additional request parameters and doing this approach I can document those "hidden" parameters in swagger. My take is implementing an interface with methods to get headername, description, isrequired and defaultvalue.Nymph
I'm using your solution for a while now, but I've just encountered an issue with this answer: If the header-field is marked as "required", SwaggerUI (maybe other clients as well) won't accept any String-value for the field. Type should instead be string (lowercase) SourceHardbitten
This looks good. Just adding a note that it is for .NET Core and not Framework.Baskett
D
13

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>();
Dieterich answered 9/3, 2021 at 5:23 Comment(2)
Thanks, it is working for me. I using .NET 5Orthodontist
Thanks, it helped me! Its working in .NET 6 tooMingo
P
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.

Patricapatrice answered 16/9, 2019 at 12:27 Comment(0)
P
5

Another customized implementation for:

  • Web API (.Net 5)
  • Swashbuckle.AspNetCore.Swagger (6.2.3)
  • Swashbuckle.AspNetCore.SwaggerGen (6.2.3)
  • Swashbuckle.AspNetCore.SwaggerUI (6.2.3)

Following some of the answers from this thread did get me a required field for Authorization. However I had run into a different problems. I need to have the followings fixed:

  • Display a lock sign beside API actions where authentication is required. For anonymous actions there is no point having a required Authorization field.
  • For every API endpoi I did not want to input the Authorization key. It becomes a redundant work if we are to test couple of APIs at one go. So I needed a single point where I would put the Auth key and execute the APIs from the Swagger UI. The Swagger UI would handle the Auth part where required.
  • I did not want to add custom filter or codes in the controller actions where I might have to edit many actions.
  • Last but not the least, I had a problem where I did get the required Authorization field on the Swagger UI but that was not being post back in request header along the other API fields.

To overcome the above issues I have done the followings:

  • Create a IOperationFilter type filter to indicate which API endpoints requires authentication and which ones are anonymous type
  • A button on the Swagger UI to bring a popup to input my Auth token that would be used automatically with the API calls from the Swagger UI

Here are the codes:

#Step-1: The custom IOperationFilter type filrer:

public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
    if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor descriptor)
    {
        // If [AllowAnonymous] is not applied or [Authorize] or Custom Authorization filter is applied on either the endpoint or the controller
        if (!context.ApiDescription.CustomAttributes().Any((a) => a is AllowAnonymousAttribute)
            && (context.ApiDescription.CustomAttributes().Any((a) => a is AuthorizeAttribute)
                || descriptor.ControllerTypeInfo.GetCustomAttribute<AuthorizeAttribute>() != null))
        {
            if (operation.Security == null)
                operation.Security = new List<OpenApiSecurityRequirement>();

            operation.Security.Add(
                new OpenApiSecurityRequirement{
                {
                    new OpenApiSecurityScheme
                    {
                        Name = "Authorization",
                        In = ParameterLocation.Header,
                        BearerFormat = "Bearer token",

                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        }
                    },                            
                    new string[]{ }
                }
            });
        }
    }
}

Then in the startup.cs file, within the ConfigureServices method add the filter like this:

services.AddSwaggerGen(options =>
{
    ...
    options.OperationFilter<AddRequiredHeaderParameter>();
    ...
    ...
}

Doing the above will add an icon to the API endpoints where Authentication is required. Here is the result: enter image description here

#Step-2: Then we need the Auth token input UI. Add the following code right after the line in the startup.cs where you have added the IOperationFilter filter:

options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{                                
    Name = "Authorization",
    Type = SecuritySchemeType.Http,
    Scheme = "Bearer",
    BearerFormat = "JWT",
    In = ParameterLocation.Header,
    Description = "JWT Authorization header. \r\n\r\n Enter the token in the text input below.,
});

This will get you a Authorize button at the top of the API descriptor page. Clicking the button will bring a popup window where you can input the Auth token and have it passed down with each API call.

enter image description here

enter image description here

Potaufeu answered 30/10, 2021 at 12:49 Comment(3)
will you please help me with how you can opt out that the listed endpoint should require Authorization? I tried your solution I can replicate the UI for auth details but not able to figure out how should I attach that header to a single endpoint onlyNewsy
i need same for .net framework 4.5..any idea plz?Mandamus
@SHEKHARSHETE have you tried the above mentioned steps? The libraries are different but the approach should be the same. What error do you get?Potaufeu
G
4

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.

Goldi answered 5/8, 2020 at 2:8 Comment(1)
This approach works only for none DefaultHeader Data like User-Agent, Authorization, etc.Kenweigh
R
3

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

Residual answered 10/3, 2021 at 23:57 Comment(0)
S
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.

Scutate answered 31/7, 2018 at 7:47 Comment(1)
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.Roddie
M
2

For me I just wanted to have custom headers to be passed from the Swagger UI.

Thanks to @M.Saeed Palideh for providing the answer.

For this purpose, I have created a filter named SwaggerHeaderParameterFilter:

Filters/SwaggerHeaderParameterFilter.cs

namespace SwagApi.Filters
{
    using System.Collections.Generic;
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;

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

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

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

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

Startup.cs

namespace SwagApi
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSwaggerGen(o => o.OperationFilter<SwaggerHeaderParameterFilter>());
        }
    }
}

I don't wanted them to be required, so I made Required as false.

This appears as shown below:

enter image description here

Mingo answered 28/9, 2023 at 8:30 Comment(0)
N
-1

Not sure if it was answered with the 2021 Sep release for .net 5.0 but I took Rami'es answer and adapted it to the following:

namespace PartnerLicense
{
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;
    using Walter.Web.FireWall.Reseller;

    public class AddRequiredHeaderParameter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {

            operation.Parameters.Add(new()
            {
                Description = "Add your reseller ID here",
                Name = HeaderKeys.ResellerId,
                In = ParameterLocation.Header,
                Required = true
            });
        }
    }
}
Neume answered 24/9, 2021 at 7:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.