How to use Swagger in ASP.Net WebAPI 2.0 with token based authentication
Asked Answered
A

2

30

I have a ASP.Net WebApi with token based authentication and I want to use swagger to create documentation for this RestApi.

The Api has for now only 2 methods, one for requesting a token i.e. http://localhost:4040/token and the other one is for creating a notification. The returned bearer token is sent like follows:

using (var client = new HttpClient())
{
    // setup client
    client.BaseAddress = new Uri("http://localhost:4040");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);

    var serializedNotification = new JavaScriptSerializer().Serialize(notification);
    var stringContent = new StringContent(serializedNotification, Encoding.UTF8, "application/json");

    var response = await client.PostAsync("api/Notification", stringContent);
    response.EnsureSuccessStatusCode();

    // return URI of the created resource.
    return response.Headers.Location;
 }

With swagger I can see the post Notification method, however I can't do a request because I don't have a token and I don't know how to do it in swagger.

Anthologize answered 30/6, 2018 at 18:49 Comment(0)
A
66

I found the solution myself. I would like to share it in case anybody is facing the same problem. The solution is of 2 steps, first one is to request a token and the next step, is to add the token into the header request.

So the first step:

Customize the frontend to enable post request for requesting a token:

enter image description here

Add a AuthTokenOperation class to enable which inherits the IDcoumentFilter interface and implements the Apply method:

public class AuthTokenOperation : IDocumentFilter
    {
        /// <summary>
        /// Apply custom operation.
        /// </summary>
        /// <param name="swaggerDoc">The swagger document.</param>
        /// <param name="schemaRegistry">The schema registry.</param>
        /// <param name="apiExplorer">The api explorer.</param>
        public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
        {
            swaggerDoc.paths.Add("/token", new PathItem
            {
                post = new Operation
                {
                    tags = new List<string> { "Auth"},
                    consumes = new List<string>
                    {
                        "application/x-www-form-urlencoded"
                    },
                    parameters = new List<Parameter>
                    {
                        new Parameter
                        {
                            type = "string",
                            name = "grant_type",
                            required = true,
                            @in = "formData"
                        },
                        new Parameter
                        {
                            type = "string",
                            name = "username",
                            required = false,
                            @in = "formData"
                        },
                        new Parameter
                        {
                            type = "string",
                            name = "password",
                            required = false,
                            @in = "formData"
                        },
                    }
                }
            });
        }
    }

And in the SwaggerConfig class in the register method, add this action

c.DocumentFilter<AuthTokenOperation>();

to the extension method:

GlobalConfiguration.Configuration.EnableSwagger

To add the authorization token in the request header:

enter image description here

Add this operation class:

/// <summary>
    /// The class to add the authorization header.
    /// </summary>
    public class AddAuthorizationHeaderParameterOperationFilter : IOperationFilter
    {
        /// <summary>
        /// Applies the operation filter.
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="schemaRegistry"></param>
        /// <param name="apiDescription"></param>
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            if (operation.parameters != null)
            {
                operation.parameters.Add(new Parameter
                {
                    name = "Authorization",
                    @in = "header",
                    description = "access token",
                    required = false,
                    type = "string"
                });
            }
        }
    }

And in the SwaggerConfig class in the register method, add this action

c.OperationFilter<AddAuthorizationHeaderParameterOperationFilter>();

to the extension method:

GlobalConfiguration.Configuration.EnableSwagger

Of course in the Authoization field, you need to add: Bearer token_string

Anthologize answered 7/7, 2018 at 9:30 Comment(4)
I used this method, and all the information shows up in swagger. However, when I try to get an auth token, I get an "error": "unsupported_grant_type" response back. Any idea what I might have done wrong? I'm using 'password' as the grant_typeKrebs
I had the same problem with "unsupported_grant_type". The issue with mine was the @in string is case sensitive, and I had it all lowercase. Changing it to formData like the example fixed my issue.Rushy
This method (attributed to this answer) has been presented in full detail by Tim Corey in one of his YouTube video tutorials. Link: youtube.com/watch?v=zQRgB6nasUcLymphatic
Reminding once again: Make sure you add Bearer <token> in the Authorization textbox when accessing a protected resourceMicroseism
O
2

I just want to add something to the accepted answer that when autorest is used for client generation, the accepted answer is not complete for it misses the some properties.

[Fatal]OperationId is required for all operations. Please add it for 'post' operation of '/authenticate' path. Exception: There was an error during code generation when trying to add a client for the REST API Generating client code and adding to project failed Adding REST API client for failed

post = new Operation
            {
                operationId = "Auth_AccessToken",
                tags = new List<string> { "Auth" },
                produces = new List<string>
                {
                    "application/json",
                    "text/json",
                    "application/xml",
                    "text/xml"
                },
                consumes = new List<string>
                {
                    "application/x-www-form-urlencoded"
                },
                parameters = new List<Parameter>
                {
                    new Parameter
                    {
                        type = "string",
                        name = "grant_type",
                        required = true,
                        @in = "formData"
                    },
                    new Parameter
                    {
                        type = "string",
                        name = "username",
                        required = true,
                        @in = "formData"
                    },
                    new Parameter
                    {
                        type = "string",
                        name = "password",
                        required = true,
                        @in = "formData"
                    },
                    new Parameter
                    {
                        type = "string",
                        name = "client_id",
                        required = true,
                        @in = "formData"
                    },
                    new Parameter
                    {
                        type = "string",
                        name = "client_secret",
                        required = true,
                        @in = "formData"
                    }
                },
                responses = new Dictionary<string, Response>
                {
                    {"200", new Response{ description = "OK", schema = new Schema{ type = "object"} } }
                }
            }

you need to add the operationId and responses for autorest to work properly.

Omeara answered 21/5, 2020 at 3:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.