user2245758
user2245758

Reputation:

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

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 something to do with it.

Upvotes: 88

Views: 180193

Answers (12)

Zaki Mohammed
Zaki Mohammed

Reputation: 1027

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

Upvotes: 3

Md Rahatur Rahman
Md Rahatur Rahman

Reputation: 3246

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

Upvotes: 5

Walter Verhoeven
Walter Verhoeven

Reputation: 4431

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
            });
        }
    }
}

Upvotes: 0

Wille Esteche
Wille Esteche

Reputation: 1839

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>();

Upvotes: 143

M.Saeed Palideh
M.Saeed Palideh

Reputation: 191

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>();

Upvotes: 13

Adebayo Vicktor
Adebayo Vicktor

Reputation: 89

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

Upvotes: 3

Sh.Imran
Sh.Imran

Reputation: 1033

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.

Upvotes: 4

Gennady Maltsev
Gennady Maltsev

Reputation: 401

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

Upvotes: 26

Ramy M. Mousa
Ramy M. Mousa

Reputation: 5943

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.

Upvotes: 91

Rajat Nigam
Rajat Nigam

Reputation: 109

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.

Upvotes: 7

Pavel Agarkov
Pavel Agarkov

Reputation: 3783

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

Upvotes: 67

Victor Sharovatov
Victor Sharovatov

Reputation: 633

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.

Upvotes: 2

Related Questions