Search code examples
asp.netasp.net-web-apiwindows-phone-8.1liveid

Login from Universal App to Web Api using Live Id


I'm trying to implement following functionality:

  1. User signs in into Live Id account from Windows Phone 8.1 (or Universal) app.
  2. App accesses Web Api that I develop with ASP.NET Web Api 2
  3. In this Web Api I need to authenticate the user.
  4. Later, I want to authenticate same user in web app

Here is what I'm doing, and it doesn't work.

In my Windows Phone App:

var authClient = new LiveAuthClient("http://myservice.cloudapp.net");
LiveLoginResult result = await authClient.LoginAsync(new string[] { "wl.signin" });

if (result.Status == LiveConnectSessionStatus.Connected)
{
    connected = true;
    var identity = await ConnectToApi(result.Session.AuthenticationToken);
    Debug.WriteLine(identity);
}

And then

private async Task<string> ConnectToApi(string token)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri("http://myservice.cloudapp.net/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // HTTP GET
        HttpResponseMessage response = await client.GetAsync("api/values");
        if (response.IsSuccessStatusCode)
        {
            string result = await response.Content.ReadAsStringAsync();
            return result;
        }
        else
            return response.ReasonPhrase;
    }
}

And then in my web api I have following

public void ConfigureAuth(IAppBuilder app)
{

    app.UseMicrosoftAccountAuthentication(
        clientId: "my client id",
        clientSecret: "my secret");

}

I registered http://myservice.cloudapp.net as redirect url.

The problem is authentication doesn't work, web api actions do not recognize the user.


Solution

  • I got it totally wrong. First, I actually need to use app.UseJwtBearerAuthentication method. The example was found here http://code.lawrab.com/2014/01/securing-webapi-with-live-id.html. But when I tried, I got this error in the output

    IDX10500: Signature validation failed. Unable to resolve SecurityKeyIdentifier: 'SecurityKeyIdentifier ( IsReadOnly = False, Count = 1, Clause[0] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause )

    This one took me a while to figure out, until I found this post: JwtSecurityTokenHandler 4.0.0 Breaking Changes?

    Putting these things together, I got the solution that seems to work now in my testing environment:

    public void ConfigureAuth(IAppBuilder app)
        {
            var sha256 = new SHA256Managed();
            var sKey = "<Secret key>" + "JWTSig";
            var secretBytes = new UTF8Encoding(true, true).GetBytes(sKey);
            var signingKey = sha256.ComputeHash(secretBytes);
            var securityKeyProvider = new SymmetricKeyIssuerSecurityTokenProvider("urn:windows:liveid", signingKey);
            var securityKey = securityKeyProvider.SecurityTokens.First().SecurityKeys.First();
    
            var jwtOptions = new JwtBearerAuthenticationOptions()
            {
                //AllowedAudiences = new[] { "<url>" },
                //IssuerSecurityTokenProviders = new[] 
                //{ 
                //  new SymmetricKeyIssuerSecurityTokenProvider("urn:windows:liveid",signingKey)
                //},
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
                {
                    IssuerSigningKeyResolver = (token, securityToken, keyIdentifier, validationParameters) =>
                        {
                            return securityKey;
                        },
                    ValidAudience = "<url>",
                    ValidIssuer = securityKeyProvider.Issuer
                }
    
            };
            app.UseJwtBearerAuthentication(jwtOptions);
    
        }