Asana OAuth in a Windows Program


#1

I don’t quite understand what to do with the User Authorization Endpoint.

To recap (this is a continuation of some of my other posts), I have a C# .NET Windows application that needs to have an interface to asana. It is a customer service application where the users keep track of service calls and issues we are working on for customers. We might have a case #1005590 in my application that has an asana ticket where people are also discussing. When users look at the case in the app, I want to call into asana and build a grid of stories people have posted there.

I have this all working with a PAT but now I need to use OAuth.

So the request I just issued is: https://app.asana.com/-/oauth_authorize?response_type=code&client_id=x&redirect_uri=x&state=x

If I type this in a browser, I get back:
Please copy this code, switch to your application, and paste it there: , plus a code.
Paste it there, where?

If I run the request through my code, with that uri passed into MakeRequest() like so:

private string MakeRequest(string uri)
{
string json;
string error;

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
        HttpWebRequest req = WebRequest.Create(uri) as HttpWebRequest;
        req.KeepAlive = false;
        SetBasicAuthentication(req);
        try
        {
            using (HttpWebResponse response = req.GetResponse() as HttpWebResponse)
            {
                using (var sr = new StreamReader(response.GetResponseStream()))
                {
                    // Oh, is there a token somewhere in here???
                    json = sr.ReadToEnd();
                }
                return json;
            }
        }
        catch (WebException e)
        {
            error = e.Message;
            Console.WriteLine(error);
            return "";
        }
    }
    void SetBasicAuthentication(HttpWebRequest req)
    {
        req.PreAuthenticate = true;
        req.Headers.Add("Authorization", "0/fxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");   // replace AccessToken with your actual generated Access Token
    }

I get back a very long json string which looks like it’s for logging into asana. It starts out: \n\n\nAsana - Log In

If I save that to a file with html as the extension (as an experiment because I was wondering what this was), it renders the asana login page.

I am at a loss what my next step is.


#2

I figured everything out! I have one question. Here is my code.

    ' *** USER AUTHORIZATION ENDPOINT ***
    Dim uri As String = "https://app.asana.com/-/oauth_authorize?response_type=code&client_id=etc...

    Dim process As System.Diagnostics.Process = New System.Diagnostics.Process()
    process.StartInfo.FileName = uri
    process.StartInfo.Verb = "open"
    process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal

    Try
        process.Start()
    Catch
    End Try

    Dim tokenCode As String
    ' Put here the value following "Please copy this code, switch to your application, and paste it there:" 
    tokenCode = "x/xxxxxxxxxxxxxxxxxxxxxxxx"

When it displays the web page instructing me “please copy this code…” is there any way my application can screen-scrape the code and capture it myself so my application can paste it into tokenCode and not bother the user to do it???


#3

I have another question about not bothering the user. It is correct that the user will have to allow asana to be accessed by our application every time they start our application? That is, my application is usually running on each person’s PC from 8:00 - 4:30. So they would have to get used to allowing access and copy/pasting the token every morning when they start their day? But when the token expires after each hour of time they’re given, I can do that refresh behind the scenes?

Thank you.


#4

Hi @MMOCK, users shouldn’t have to copy a refresh code. Check out this thread in the community: Feature Request: Specify Comment Author.

While I don’t have any #C expertise to help you with your specific example, we can help with the general OAuth process.


#5

Great. That is half the question. But they will have to authenticate once per day? Asana can’t authenticate once and then remember, forever?


#6

No, the user will only have to authenticate once; no need for once per day.

Overall, there are two separate pieces of an OAuth-based authentication solution:

  1. Initial authentication
  2. Refreshing the authentication

(1.) Initial Authentication:
As you discovered, OAuth is really a web-based process and that’s why it’s tougher to accomplish in a desktop application. The way to do it in a desktop app is to embed a webbrowser control in your app and do the authentication handshaking that way. I don’t have my own code to provide such an approach but there are multiple examples available online which take that approach. I can’t personally vouch for any of them but check these out:

https://stackoverflow.com/a/22182612/3073617

https://github.com/chilkatsoft/OAuth2-CSharp-Desktop

https://github.com/box/box-windows-sdk-v2

At the end of the initial authentication process, you’ll end up with an authentication token and a refresh token, both of which you’ll want to save in a record associated with that user.

(2.) Refreshing:
Once you have the above tokens, you’ll then use the authentication token in your Asana API calls. That token will work for about an hour, at which point it will expire (Asana has their tokens set to expire once per hour). You’ll know it’s expired because instead of getting a valid result back from your API call, you’ll get back an error 401 - “Unauthorized”. When that happens, take the refresh token and use it to get a new authentiation token which will be good for another hour. Because of this behind-the-scenes once-per-hour refresh, the user never has to do any re-authentication. Here’s the code I use to do this refresh:

    public string RefreshOAuthToken(string usersRefreshToken)
    {
        string data = string.Format("client_id={0}&client_secret={1}&redirect_uri={2}&refresh_token={3}&grant_type=refresh_token", myClientId, myClientSecret, myRedirectUri, usersRefreshToken);
        byte[] dataStream = Encoding.UTF8.GetBytes(data);
        string urlPath = "https://app.asana.com/-/oauth_token";
        WebRequest webRequest = WebRequest.Create(urlPath);
        webRequest.Method = "POST";
        webRequest.ContentType = "application/x-www-form-urlencoded";
        webRequest.ContentLength = dataStream.Length;
        Stream newStream = webRequest.GetRequestStream();
        newStream.Write(dataStream, 0, dataStream.Length);
        newStream.Close();
        try
        {
            WebResponse webResponse = webRequest.GetResponse();
            Stream dataStream2 = webResponse.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream2);
            string responseFromServer = reader.ReadToEnd();
            var authResponse = JsonConvert.DeserializeObject<AuthRenewalResponse>(responseFromServer);
            return authResponse.AccessToken;
        }
        catch (Exception ex)
        {
            return string.Empty;
        }
    }