1

I have a asp.net application with a front end and a web api portion. I would like a mobile app to be able to use the protected web api endpoints. This means I need to log in and handle the auth token in the native mobile application.

Right now, the only way I can login to my asp.net application is by going through the default asp.net /Account/Login page. When I post to the login endpoint, the body that is returned just contains the html of my application. The token is then stored in cookies by asp.net.

Since I am trying to login from my native mobile app, I do not need the html response, and would not like to have to go through cookies to get my token.

Is it possible to create a separate login endpoint that only returns the token and/or user details, rather than the html content of my application? Is this a bad idea?

For reference, this is the default asp.net login handler i was referring to.

        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }
Nick H
  • 1,925
  • 2
  • 15
  • 23

2 Answers2

1

I would consider a combination of JWT/Owin. Basically, you need a mechanism that will issue tokens (OAuth) after successful login and then you need a middleware that will consume the token bearer from any subsequent request's http header and grant(or deny) the access (using standard [Authorize] decorator). Here is very nice example of how to use JWT (Json Web Tokens).

If you're not familiar with OWIN/Katana itself there are very nice articles on official website. It will be very useful. You will basically just need two OWIN middlewares, the UseOAuthAuthorizationServer and UseJwtBearerAuthentication which comes from a few NuGet packages. Just follow the example above.

Only to be complete here, you mention storing the token beares in native mobile application, make sure you store them on appropriate locations either in Android or iOS.

Community
  • 1
  • 1
Ivan Sivak
  • 7,178
  • 3
  • 36
  • 42
0

On my Phone Apps I call server side APIs using https. I have provided sample code here of how I authorize users...this code has been modified so as not to show my actual process. You'll have to modify it to meet your needs. But it does show an approach that calls web services only.

On your Service Side create the following Attribute:

using System.Text;
using System.Security.Cryptography;
using System.Web.Http.Filters;
using System.Web.Http.Controllers;
using System.Net.Http;

  public class RequireHttpsAttribute : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (actionContext.Request.RequestUri.Scheme !=Uri.UriSchemeHttps)
            {
                actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                {
                    ReasonPhrase = "HTTPS Required"
                };
            }
            else
            {

                string UserName; 
                String Password;

                if (actionContext.Request.Headers.Any(p => p.Key == "UserName") &&
            actionContext.Request.Headers.Any(p => p.Key == "UserName"))
                {
                    UserName = actionContext.Request.Headers.Where(p => p.Key ==                                            "UserName").FirstOrDefault().Value.FirstOrDefault();

            Password = actionContext.Request.Headers.Where(p => p.Key ==                                            "UserName").FirstOrDefault().Value.FirstOrDefault();

                //do authentication stuff here..
            If(Authorized())
            {
                 base.OnAuthorization(actionContext);
                             return;
            }
            Else
        {

                actionContext.Response = new HttpResponseMessage                            (System.Net.HttpStatusCode.Forbidden)
                        {
                                ReasonPhrase = "Invalid User or Password"
                        };
            }

                }

                actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)
                {
                    ReasonPhrase = "HTTPS Required"
                };


            }
        }

        return ReasonPhrase;
    }

On your client side make request like this:

string ResponseText= String.Empty();
using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri("https://YOURAPI/");

                    client.DefaultRequestHeaders.Accept.Clear();
                    //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue                   ("text/json"));
                    client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));

                    client.DefaultRequestHeaders.Add("UserName", UserName);
                    client.DefaultRequestHeaders.Add("Password", Password);
                    // New code:
                    HttpResponseMessage response = await client.GetAsync            ("api/YOURAPIENDPOINT").ConfigureAwait(continueOnCapturedContext: false);
                    if (response.IsSuccessStatusCode)
                    {
                        ResponseText = await response.Content.ReadAsStringAsync();
                    }
                }

The API method should look something like this:

    [RequireHttps]
    public YOURAPI Get(int id)
    {
       //if you got this far then the user is authorized.
    }

Your mileage may vary. I have not tested this code as modified. But you should get the idea of how to accomplish what you want.

Ibrahim Malluf
  • 657
  • 4
  • 6