Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication to Box in a C# desktop application using the Box Windows SDK v2 library

Seems like this should be a simple thing to do, but I can't find an example or thorough enough documentation to figure it out.

I have a C# desktop application that I'd like to integrate with Box via the Box API. I assume that using the Box Windows SDK v2 for .NET will be the way to go.

Can someone point me to a simple, bare-bones example that will work for a desktop application?

like image 287
jpreed00 Avatar asked Mar 02 '14 05:03

jpreed00


1 Answers

I decided to try and figure this one out myself. Even though OAuth2 supports non-browser based authentication, apparently Box.com has decided not to implement it (or, at least, I can find no mention of how to do it anywhere).

So, the only alternative for a desktop based application is to somehow intercept the URL redirect that occurs and yank the authentication information out of the query string parameters.

However, as IE has fallen behind the times recently, and I'm working in C# and .NET, I decided to look into embedding another browser rather than using the built-in browser control. I went with Awesomium--a managed .NET Chromium wrapper.

So, without further ado, I present the bare-bones example that will work for a desktop application.

My solution has two forms, one that I use purely as the "browser" and the main form: frmMain contains all the code and frmBrowser contains the Awesomium control.

using Newtonsoft.Json.Linq;
using System.Web;

private static frmBrowser browser = null;
private const string BoxClientId = "{your client id}";
private const string BoxSecret = "{your secret}";    

private void authenticateWithBox()
{
   browser = new frmBrowser();
   browser.Show();

   browser.webControl1.Source = new Uri("https://www.box.com/api/oauth2/authorize?response_type=code&client_id=" + BoxClientId + "&redirect_uri=https://localsess");
   browser.webControl1.AddressChanged += new Awesomium.Core.UrlEventHandler(webControl1_AddressChanged);
}

void webControl1_AddressChanged(object sender, Awesomium.Core.UrlEventArgs e)
{
  //MessageBox.Show(e.Url.ToString());
  if (e.Url.Host == "localsess")
  {
    NameValueCollection parms = HttpUtility.ParseQueryString(e.Url.Query);
    if (parms.AllKeys.Contains("error"))
    {
       MessageBox.Show("Error connecting to Box.com: " + parms["error"] + " " + parms["error_description"]);
    }
    else
    {
        boxContinue(parms["code"]);
    }
  }
}

The above code is where the magic happens. The AddressChanged event fires every time the URL being displayed by the web control changes. So you have to set your redirect URL to something unique you can detect--it doesn't even have to exist, as shown in the example code. Then you can just yank out the parameters that you need and continue the authentication process.

string postToUrl(string url, string data)
{
  string results = String.Empty;
  WebRequest req = WebRequest.Create(url);
  req.Method = WebRequestMethods.Http.Post;
  byte[] byteArray = Encoding.UTF8.GetBytes(data);
  req.ContentType = "application/x-www-form-urlencoded";
  req.ContentLength = byteArray.Length;
  Stream dataStream = req.GetRequestStream();
  dataStream.Write(byteArray, 0, byteArray.Length);
  dataStream.Close();
  WebResponse res = req.GetResponse();
  dataStream = res.GetResponseStream();
  StreamReader reader = new StreamReader(dataStream);
  results = reader.ReadToEnd();
  return results;
}

void boxContinue(string code)
{
  browser.Close();
  browser.Dispose();
  string json = postToUrl("https://www.box.com/api/oauth2/token", "code=" + code + "&grant_type=authorization_code&client_id=" + BoxClientId + "&client_secret=" + BoxSecret);
  JToken token = JObject.Parse(json);

  string access_token = (string)token.SelectToken("access_token");
  string refresh_token = (string)token.SelectToken("refresh_token");
}

void boxRefresh(string refresh_token)
{
  string json = postToUrl("https://www.box.com/api/oauth2/token", "grant_type=refresh_token&refresh_token=" + refresh_token + "&client_id=" + BoxClientId + "&client_secret=" + BoxSecret);
  JToken token = JObject.Parse(json);

  string access_token = (string)token.SelectToken("access_token");
  string new_refresh_token = (string)token.SelectToken("refresh_token");
}

The rest of the code is just your run-of-the-mill authentication code that uses the tokens and whatnot from previous requests to get more tokens, etc. Box uses "refresh_tokens" to enable to you get additional access tokens, I show an example of how to do that, too.

If you notice any errors or have any comments, etc. just leave a comment.

like image 121
jpreed00 Avatar answered Oct 29 '22 23:10

jpreed00