Search code examples
c#resthttpwebrequestsharepoint-2013

Rest Post call with Authentication Token


I'm trying to send a Post request to SharePoint Online (Claims Based Auth Site) from my client application (WPF application). In this case it should be an update to a ListItem to change the 'Title' to 'Test'.

I'm retrieving the CookieContainer via MsOnlineClaimsHelper Class which successfully returns me an auth token.

But when i try to send the request the response is The remote server returned an error: (403) Forbidden.

WebRequest Code

try
{
    var claimshelper = new MsOnlineClaimsHelper(baseUrl, _userName, _password);
    var request = (HttpWebRequest)WebRequest.Create(baseUrl + "/" + url);

    request.CookieContainer = claimshelper.CookieContainer;
    request.Method = "POST";
    request.Headers.Add("X-HTTP-Method", "MERGE");
    request.Headers.Add("If-Match", "*");
    request.Accept = "application/json;odata=verbose";

    using (var streamWriter = new StreamWriter(request.GetRequestStream()))
    {
        streamWriter.Write(json);
        streamWriter.Flush();
    }

    var webResp = request.GetResponse() as HttpWebResponse;
    var theData = new StreamReader(webResp.GetResponseStream(), true);
    string payload = theData.ReadToEnd();
}
catch (Exception ex)
{


}

Rest Url:

/_api/lists/getbytitle('SampleList')/items(1)

Json Payload:

string json = "{ '__metadata': { 'type': 'SP.Data.SampleListListItem' }, 'Title': 'Test'}";

Error:

The remote server returned an error: (403) Forbidden.


Solution

  • This error occurs since SharePoint 2013 REST service requires the user to include a Request Digest value with each create, update and delete operation. This value is then used by SharePoint to identify non-genuine requests.

    How to provide Request Digest value

    In MsOnlineClaimsHelper class (MsOnlineClaimsHelper.cs file) add the following method to request Form Digest value:

    /// <summary>
    /// Request Form Digest value
    /// </summary>
    /// <returns></returns>
    private string GetFormDigest()
    {
        var endpoint = "/_api/contextinfo";
        var request = (HttpWebRequest) WebRequest.Create(_host.AbsoluteUri + endpoint);
    
        request.CookieContainer = new CookieContainer();
        request.Method = "POST";
        //request.Accept = "application/json;odata=verbose";
        request.ContentLength = 0;
    
        using (var response = (HttpWebResponse)request.GetResponse())
        {
             using (var reader = new StreamReader(response.GetResponseStream()))
             {
                 var result = reader.ReadToEnd();
    
                 // parse the ContextInfo response
                 var resultXml = XDocument.Parse(result);
    
                 // get the form digest value
                 var e = from e in resultXml.Descendants()
                                     where e.Name == XName.Get("FormDigestValue", "http://schemas.microsoft.com/ado/2007/08/dataservices")
                                select e;
                 _formDigest = e.First().Value;   
             }
        }
        return _formDigest;
    }
    

    and FormDigest property:

    private string _formDigest;
    public string FormDigest
    {
        get
        {
           if (_formDigest == null || DateTime.Now > _expires)
           {
               return GetFormDigest();
           }
           return _formDigest;
        }
    }
    

    How to perform an update operation for a ListItem using SharePoint 2013 REST API

    The following example demonstrates how to perform an update of a list item using the provided implementation for requesting a Form Digest

    Key Points:

    • X-RequestDigest header is used to specify Form Digest value
    • Request Content Type have to be specified

    Example:

    var userName = "[email protected]";
    var password = "password";
    var payload = "{ '__metadata': { 'type': 'SP.Data.TasksListItem' }, 'Title': 'New Tasl'}";  //for a Task Item
    
    
    try
    {
        var claimshelper = new MsOnlineClaimsHelper(baseUrl, _userName, _password);
        var request = (HttpWebRequest)WebRequest.Create(baseUrl + "/" + endpointUrl);
    
        request.CookieContainer = claimshelper.CookieContainer;
        request.Headers.Add("X-RequestDigest", claimshelper.FormDigest);
        request.Method = "POST";
        request.Headers.Add("X-HTTP-Method", "MERGE");
        request.Headers.Add("If-Match", "*");
        request.Accept = "application/json;odata=verbose";
        request.ContentType = "application/json;odata=verbose";
    
        using (var writer = new StreamWriter(request.GetRequestStream()))
        {
            writer.Write(payload);
            writer.Flush();
        }
    
        var response = request.GetResponse() as HttpWebResponse;
        //...
     }
     catch (Exception ex)
     {
        //Error handling goes here.. 
     }