Search code examples
c#asp.net-mvccookiesasp.net-web-api2asp.net-identity-2

Authenticating with MVC application from a Web API authentication


Overview:

I have a Web API sat on ABC domain and an MVC application sat on XYZ domain.

When a user authenticates with the API, I am making a call to the MVC application which replicates the login method and sets an cookie for the MVC app, thus allowing the user to be authenticated on both applications from one endpoint.

Problem:

The call from the API to the MVC application is working fine, however, the cookie is not being set. Therefore, I am still requested to login when I visit my MVC application after authenticating with the API.

Web API call to the MVC Application:

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://xyz.co.uk");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var content = new FormUrlEncodedContent(new[] 
    {
        new KeyValuePair<string, string>("refreshTokenId", token.Id)
    });

    // HTTP POST
    HttpResponseMessage response = await client.PostAsync("Account/LoginFromAPI", content);
}

MVC application login (from API call):

[HttpPost]
[AllowAnonymous]
public void LoginFromAPI(string refreshTokenId)
{
    RefreshToken refreshToken = null;

    // Get refresh token from the API database
    using(var api = new APIContext())
    {
        refreshToken = api.RefreshTokens.SingleOrDefault(x => x.Id == refreshTokenId);
    }

    if (refreshToken != null)
    {
        // Find the user in the MVC application database
        var user = this.UserManager.FindByEmail(refreshToken.Subject);

        if (user !=  null)
        {
            // The below code works fine for normal login through the MVC application, 
            // but not by the call from the API
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
            ClaimsIdentity identity = user.GenerateUserIdentity(this.UserManager);
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = rememberMe }, identity);
        }
    }
}

Solution

  • The problem is that you're setting a Cookie for the XYZ domain. Cookies are domain specific, so when you send a request to ABC domain, the cookie isn't attached and vice versa. What you need to do is to setup an authentication server that will provide a Single Sign On functionality to your application. You may look into Active Directory Federation Services or ThinkTecture IdentityServer. All requests will be authenticated from your authentication server and redirected to the target server for processing. This is how Microsoft Accounts and many other account management services achieve Single Sign On. Good luck!