Desktop Application: Stack Exchange API – OAuth 2.0

Recently, we need to integrate Stack Exchange authentication to our Desktop Application. To obtain Access Token, someone tried to send web request to the specified url with parameters, but this didn’t work.

Ref to Stack Exchange API Authentication Document:

Desktop Applications

Desktop applications cannot participate directly in OAuth 2.0 flows, however the embeddable browser controls available in most frameworks make it possible to work around this limitation.

Desktop applications should use the implicit client-side flow, hosting the process within a browser control. For redirect_uri, a value of https://stackexchange.com/oauth/login_success should be used. Upon a successful authentication, access_token will be placed in the url hash as with a standard implicit authentication.

What’s the implicit client-side flow:

1. Open a new window at https://stackexchange.com/oauth/dialog, with these query string parameters

  • client_id
  • scope (details)
  • redirect_uri – must be under an apps registered domain
  • state – optional

2. The user approves your app
3. The user is redirected to redirect_uri, with these parameters in the hash

  • access_token
  • expires – optional, only if scope doesn’t contain no_expiry

After understanding the above flow, we’ll step through the flow with examples.

Firstly, we need to register for an app key: http://stackapps.com/apps/oauth/register

Secondly, by using the Client Id generated in the above step, the url with parameters will be like this:

https://stackexchange.com/oauth/dialog?client_id=<Your ClientID>&scope=no_expiry&redirect_uri=https://stackexchange.com/oauth/login_success

In this step, we could create a new window with WebBrowser control and navigate to the above url, but the default IE version was not the same as my OS(Win8.1 IE11), so I created a method to Fix this issue, used the FEATURE_BROWSER_EMULATION feature: http://msdn.microsoft.com/en-us/library/ie/ee330730(v=vs.85).aspx

private void IEbrowserFix()
{
            try
            {
                Microsoft.Win32.RegistryKey regDM = Registry.CurrentUser;
                string KeyPath = "SOFTWARE\\Microsoft\\Internet Explorer\\MAIN\\FeatureControl\\FEATURE_BROWSER_EMULATION";

                regDM = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(KeyPath, false);
                if (regDM == null)
                {
                    regDM = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(KeyPath);
                }

                object Sleutel = null;
                if ((regDM != null))
                {
                    string location = System.Environment.GetCommandLineArgs()[0];
                    string appName = System.IO.Path.GetFileName(location);

                    Sleutel = regDM.GetValue(appName);
                    if (Sleutel == null)
                    {
                        //Sleutel onbekend
                        regDM = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(KeyPath, true);
                        Sleutel = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(KeyPath, Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree);

                        //What OS are we using
                        Version OsVersion = System.Environment.OSVersion.Version;

                        if (OsVersion.Major == 6 & OsVersion.Minor == 1)
                        {
                            //WIN 7
                            ((RegistryKey)Sleutel).SetValue(appName, 9000, Microsoft.Win32.RegistryValueKind.DWord);
                        }
                        else if (OsVersion.Major == 6 & OsVersion.Minor == 2)
                        {
                            //WIN 8
                            ((RegistryKey)Sleutel).SetValue(appName, 10000, Microsoft.Win32.RegistryValueKind.DWord);
                        }
                        else if (OsVersion.Major == 6 & OsVersion.Minor == 3)
                        {
                            <strong>//WIN 8.1</strong>
<strong>                            ((RegistryKey)Sleutel).SetValue(appName, 11001, Microsoft.Win32.RegistryValueKind.DWord);</strong>
                        }
                        else if (OsVersion.Major == 5 & OsVersion.Minor == 1)
                        {
                            //WIN xp
                            ((RegistryKey)Sleutel).SetValue(appName, 8000, Microsoft.Win32.RegistryValueKind.DWord);
                        }

                        ((RegistryKey)Sleutel).Close();
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
}

RedirectForm.cs:

public partial class RedirectForm : Form
{
        public RedirectForm()
        {
            InitializeComponent();
        }
        public string Token
        {
            get;
            set;
        }

        public RedirectForm(string url)
        {
            InitializeComponent();

            webBrowser1.Navigate(url);
        }

        private void RedirectForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            NameValueCollection urlParameters = HttpUtility.ParseQueryString(webBrowser1.Url.ToString());

            // extract the access token from the url.
            string accessToken = urlParameters["https://stackexchange.com/oauth/login_success#access_token"];
            if(accessToken!=null)
            {
                //MessageBox.Show(accessToken);
                this.Token = accessToken;
            }
        }

        private void IEbrowserFix()
        {
            //...Omitted...
        }

        private void RedirectForm_Load(object sender, EventArgs e)
        {
            IEbrowserFix();
        }
}

MainFrom.cs:

private void button1_Click(object sender, EventArgs e)
{
            string url2 = "https://stackexchange.com/oauth/dialog?client_id="+txtClientID.Text+"&scope=no_expiry&redirect_uri=https://stackexchange.com/oauth/login_success";

            using( RedirectForm rf =new RedirectForm(url2))
            {
                DialogResult result=rf.ShowDialog();
                if(result == DialogResult.Cancel)
                {
                    txtToken.Text = rf.Token;
                }
            }
}

Screenshot:

Auth1

Obtained Access Token:

Auth2

2 thoughts on “Desktop Application: Stack Exchange API – OAuth 2.0”

  1. Hello
    thanks for your useful codes
    i have a problem how can i write answer or comment in the stack-overflow. please let me know if you have some more information .
    best regards
    hesam

    1. Hi hesam,

      I think StackOverFlow API Document has included what you need : https://api.stackexchange.com/docs

      If you still need help about this, I will create a new post to show you how to accomplish it, I’m working on something about business, maybe update this later if I have time:)

      Best Regards,
      Franklin

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>