Search code examples
c#asp.net-mvcasp.net-mvc-4asp.net-web-apiasp.net-identity

Login with Basic Authentication in web api


I'm using In-Build template for Login and Registration in Web Api.

It uses Token based Authentication .

But what I want is to login a user I want use Basic authentication, after web api will return a token then now I want to use that to to call api methods.

right now I request for login like this

var resp = $http({
            url: "/TOKEN",
            method: "POST",
            data: $.param({ grant_type: 'password', username: userlogin.username, password: userlogin.password }),
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        });

and It return me a token, which I send it with next request to call authorize methods.

But I wand to send username and password : separated like basic authentication

HttpClient client = new HttpClient();

 string authInfo = "admin" + ":" + "123456";
 authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
 client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authInfo);

 client.BaseAddress = new Uri("http://localhost:63173/TOKEN");

And server side I will decode it back to get username and password to validate user and will return authentication token.

var encoding = Encoding.GetEncoding("iso-8859-1");
                credentials = encoding.GetString(Convert.FromBase64String(credentials));

                int separator = credentials.IndexOf(':');
                string name = credentials.Substring(0, separator);
                string password = credentials.Substring(separator + 1);

But I don't know where to modify the existing code.


Solution

  • The only workaround I can think of is writing a simple Owin middleware that remaps the credentials found in the Authorization header to form fields, executed at the beginning of the Owin pipeline.

    Something similar to this:

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Use(async (ctx, n) =>
            {
                if (ctx.Request.Path == new PathString("/path/to/token")) //the same path you specified in the "TokenEndpointPath" property of "OAuthAuthorizationServerOptions"
                {
                    var authHeader = ctx.Request.Headers["Authorization"];
    
                    if (!string.IsNullOrWhiteSpace(authHeader) && authHeader.StartsWith("Basic "))
                    {
                        //parse here authHeader
                        var name = GetUsernameFromHeader(authHeader);
                        var password = GetPasswordFromHeader(authHeader);
                        //change the above lines with your parsing methods
    
                        var form = new Dictionary<string, string[]>()
                        {
                            { "grant_type", new [] {"password" }},
                            { "username", new []{ name }},
                            { "password", new [] { password}}
                        };
    
                        ctx.Set<IFormCollection>("Microsoft.Owin.Form#collection", new FormCollection(form));
                    }
                }
    
                await n.Invoke();
            });
    
    
            //app.UseWebApi... 
            //other middlewares
        }
    }
    

    I warn you that this approach just writes those values to the Owin context and will work as long as the underlying OAuthAuthorizationServerMiddleware implementation doesn't change.