65.9K
CodeProject is changing. Read more.
Home

Using Swagger in .NET Core MVC Web Services with Token Authentication

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7 votes)

Nov 2, 2017

CPOL

2 min read

viewsIcon

20613

How to configure Swagger for web services using token authentication

Introduction

I wanted to build web services in .NET Core MVC using a token authentication. When I was almost done... I found Swagger.
It looks very cool how it documents the web services and provides API testers.
But I have the following issue: Swagger was excellent discovering methods but the default parameters do not adjust to the ones required by token authentication.

Background

At this point, I believe that you should check the following links to understand what all this is about.
For the token authentication, I follow this article. It used the library OpenIdDict.

For Swagger, there is an excellent article explaining its capabilities.

Using the Code

I build two separate MVC projects: one is the token authentication service (that provides the token), and the other one is the main service (containing the information that the client will be willing to consume).

The token authentication service contains one controller with a method Auth. This method has a OpenIdConnectRequest as a parameter.
But, the post needs the header "Content-Type: application/x-www-form-urlencoded" and the body containing "grant_type=[type]&username=[username]&password=[password]".
And Swagger was unable to discover these requirements from the method signature.

To fix that, I need to remove the default parameters (the members of OpenIdConnectRequest), add the header for the content-type and add the required parameters.
To do that, I had to modify the Startup.cs adding in the ConfigureServices:

            services.AddSwaggerGen(c =>
            {
                ...
                c.OperationFilter<CustomTokenFilter>();
                ...
            });

And add the following classes:

    public class CustomTokenFilter : IOperationFilter
    {
        public void Apply(Operation operation, OperationFilterContext context)
        {
           if (operation.OperationId == "AuthPost")
            {
                operation.Consumes.Add("application/x-www-form-urlencoded");

                operation.Parameters = new List<IParameter>();

                operation.Parameters.Add(new Parameter
                {
                    Name = "grant_type",
                    @In = "formData",
                    Type = "string",
                    Required = true
                });

                operation.Parameters.Add(new Parameter
                {
                    Name = "username",
                    @In = "formData",
                    Type = "string",
                    Required = true
                });

                operation.Parameters.Add(new Parameter
                {
                    Name = "password",
                    @In = "formData",
                    Type = "string",
                    Required = true
                });
            }
        }
    }

    public class Parameter : IParameter
    {
        public string Description { get; set; }

        public Dictionary<string, object> Extensions { get; }

        public string In { get; set; }

        public string Name { get; set; }

        public bool Required { get; set; }

        public string Type { get; set; }
    }     

That fixed my problem on the token authentication service method.

On the other hand, the main service methods need the header "Authorization: bearer [token]".

So for this, I modify the ConfigureServices method of the Startup.cs in a similar manner:

c.OperationFilter<AddRequiredHeaderParameter>();

And I add the following class:

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

            operation.Parameters.Add(new Parameter
            {
                Name = "Authorization",
                @In = "header",
                Type = "string",
                Required = true
            });
        }
    }    

So now the main service API test works property.

So, this is all....

Points of Interest

Swagger is a great tool!

History

  • 2nd November, 2017: Initial version