Search code examples
c#xamluwpwindows-authenticationwcf-web-api

Passing current authentication credentials from UWP app to web service to access resources on server with these credentials


My Windows 10 UWP app is calling a WebAPI web service that I have created. I need to pass the current credentials on the client side when calling the web service so that it can access other resources using these credentials.

I also need to do this without prompting the user for credentials so that the experience is seamless.

I am able to do this with using System.Net.Http and successfully pass the current credentials to the server to use for accessing resources. This sends the request and brings back the response without any prompt. I have enabled Enterprise Authentication and Private Networks capabilities on the UWP app to make this work.

Problem: This works fine for GET requests but not for POST requests to the same server. POST requests result in the following error:

This IRandomAccessStream does not support the GetInputStreamAt method because it requires cloning and this stream does not support cloning.

I read that this was a bug on this link: PostAsync throwing IRandomAccessStream error when targeting windows 10 UWP. The workaround proposed in multiple locations for this bug is to use Windows.Web.Http instead. However, if I do this, how can I pass the default/current credentials to the server?

Here is the code that I am using to do a GET request using the current Windows credentials without prompting for it. It works flawlessly:

System.Net.Http.HttpClientHandler handler = new System.Net.Http.HttpClientHandler
{
    UseDefaultCredentials = true
    // Credentials = (NetworkCredential)System.Net.CredentialCache.DefaultNetworkCredentials
    //using either one of the above enables me to have the web service use the current credentials without prompting
};

string responseContent = string.Empty;

using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(handler))
{
    System.Net.Http.HttpRequestMessage requestMessage = new System.Net.Http.HttpRequestMessage();

    requestMessage = new System.Net.Http.HttpRequestMessage
    {
        Method = System.Net.Http.HttpMethod.Get,
        RequestUri = new Uri(strWebServiceURL)

    };

    using (System.Net.Http.HttpResponseMessage response = await client.SendAsync(requestMessage))
    {

        responseContent = await response.Content.ReadAsStringAsync();

    }

    //This also works fine
    using (System.Net.Http.HttpResponseMessage response = await client.GetAsync(strWebServiceURL))
    {

        responseContent = await response.Content.ReadAsStringAsync();

    }

Below is the code I use to do a POST request which results in the IRandomAccessStream error:

System.Net.Http.HttpClientHandler handler = new System.Net.Http.HttpClientHandler
{
    UseDefaultCredentials = true
   // Credentials = (NetworkCredential)System.Net.CredentialCache.DefaultNetworkCredentials
   //using either one of the above enables me to have the web service use the current credentials without prompting
};

string responseContent = string.Empty;

using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(handler))
{
    System.Net.Http.HttpRequestMessage requestMessage = new System.Net.Http.HttpRequestMessage();

    requestMessage = new System.Net.Http.HttpRequestMessage
    {
        Content = myMultipartFormDataContent,
        Method = System.Net.Http.HttpMethod.Post,
        RequestUri = new Uri(strWebServiceURL)

    };

    using (System.Net.Http.HttpResponseMessage response = await client.SendAsync(requestMessage))
    {

        responseContent = await response.Content.ReadAsStringAsync();

    }

    //No difference when using it this way as well
    using (System.Net.Http.HttpResponseMessage response = await client.PostAsync(strWebServiceURL, myMultipartFormDataContent))
    {

        responseContent = await response.Content.ReadAsStringAsync();

    } 

I tried using Windows.Web.Http but I don't know how I can get it to pass the current/default credentials to the server without prompting.

I have also added the WebService URL to a IE Local Intranet zone and have that zone set to automatically log in with current user name and password:

Please help!

IE Settings


Solution

  • With the new Windows.Web.Http namespace in UWP app, if you want to use the DefaultCredentials, all you have to do is turn on enterprise credentials in the manifest and the uwp app will send them out as appropriate. You don't need to configure anything on the HttpClientto make it work. Details please reference this thread.

    Since you already enable the enterprise credentials capability, you could just create HttpClient without configure. But to avoid the username and password prompt, you may need to disable the UI, for example:

    var myFilter = new HttpBaseProtocolFilter();
    myFilter.AllowUI = false;
    Windows.Web.Http.HttpClient client = new Windows.Web.Http.HttpClient(myFilter);
    Windows.Web.Http.HttpResponseMessage result = await client.GetAsync(new Uri("http://localhost:5132/api/values"));