Search code examples
c#posthttpwebrequestwebrequestassembla

3 step OATH 2.0 authentication for Assembla API POST request returns "Bad request"


I'm trying to create a tool to communicate with the Assembla API, and I'm having trouble getting the authentication right. I'm using the 3 step procedure as described here. Retrieving the PIN code is no trouble for now, though I do want to make it more intelligent in the future. I am having trouble exchanging the PIN code for a bearer token.

My code as it is:

private void button1_Click(object sender, EventArgs e)
        {
            var url = string.Format("https://api.assembla.com/token");

            var web = (HttpWebRequest)WebRequest.Create(url);

            web.Method = "POST";
            //web.Accept = "application/x-www-form-urlencoded";
            web.ContentType = "application/x-www-form-urlencoded";
            web.Headers["client_id"] = "xxxxx";
            web.Headers["client_secret"] = "xxxxxx";

            var data = string.Format("grant_type=pin_code&pin_code={0}", textBox1.Text); 

            byte[] buffer = Encoding.UTF8.GetBytes(data);
            web.ContentLength = buffer.Length;

            var postData = web.GetRequestStream();

            postData.Write(buffer, 0, buffer.Length);
            postData.Close();

            WebResponse resp = web.GetResponse();

            var sr = new StreamReader(resp.GetResponseStream());

            var result = sr.ReadToEnd().Trim();
        }

This results in an webrequest exception: The remote server returns an error: (400) Bad Request. Error is thrown on the line WebResponse resp = web.GetResponse();

I'm not sure how to get more information about the error. However, if I use http://requestmaker.com/ to fill out my credentials and pin code, it returns the same error code as well as a response body saying {"error":"invalid_request","error_description":"'client_id' required."}. I tried requestmaker both with client_id as headers and hardcoded as in Assembla's example of "https://_client_id:[email protected]/token?grant_type=pin_code&pin_code=_pin_code". Both return the same result.

This is the first time I did anything with http request, so it might be some silly overview on my part. The error is probably Assembla specific, but if somebody sees any obvious errors in my code I'd be thankful for corrective advise.


Solution

  • There is a more or less complete API in this answer for exchanging the PIN for access tokens. That API is for getting imgUr account upload tokens via OAuth. Part of the relevant function:

    // the PIN previously received 
    string myPin = "";
    
    private bool RequestToken(string CliId, string CliSecret)
    {
        // request format as per imgUR API - YMMV
        string sReq = string.Format("client_id={0}&client_secret={1}&grant_type=pin&pin={2}",
                    CliId, CliSecret, myPin);
        string url = "https://api.imgur.com/oauth2/token/";
    
        bool myResult = true;
    
        // create request for the URL, using POST method
        WebRequest request = WebRequest.Create(url);
        request.Method = "POST";
    
        // convert the request, set content format, length
        byte[] data = System.Text.Encoding.UTF8.GetBytes(sReq);
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = data.Length;
    
        // write the date to request stream
        Stream dstream = request.GetRequestStream();
        dstream.Write(data, 0, data.Length);
        dstream.Close();
    
        // ToDo: 
        // GetResponse() in Try/Catch
        // if there is an exception get the exact error
        // otherwise:
        //    read the stream and parse (json) the result to get access token
    
        return myResult;      
    }
    

    There are not a lot of differences to what you have but they all are related to formatting the request and submitting it. At least for imgUr, the docs are very specific about how the request string should look, so double check that against the docs for whatever site you are trying to access.

    Note that in most cases the result is json which will need to be parsed to get the tokens.