Contents
Introduction
Large web projects can provide partial access to the resources of their own members for third-party sites and applications. For the most part, this is achieved by using the protocol OAuth.
OAuth is an open protocol to authorization. The protocol allows to keep secret an users credentials. Working with resources of users carried out by an access token.
I understand the idea is not new, but somewhere in a parallel universe I did own library for authorization through OAuth in .NET Framework projects.
The library provides mechanisms for implementing OAuth clients, and also contains a ready-to-use clients for popular websites.
The main goal - is simplicity and minimalism. At least it was when I started to write this article. Unfortunately (or fortunately), in the process I made two new releases of the library. Using the library is still simple, but the amount of source code significantly increased. But you do not need to look at the source code of the project. So everything is fine. :-)
The main feature - it is possible to obtain basic information from the user profile. Thus, you can get email address, phone number, name of the user, a link to the site and a photo. It is what it is first necessary for most sites, which support users authentication through OAuth protocol.
The library is focused on the web, but it may well be used in other types of projects.
The source code is open, written in C# and is licensed under the Apache License Version 2.0.
For the library requires the .NET Framework 3.5 or later.
The source code of the project and examples created in Visual Studio 2010 (SP1) for .NET Framework 4.0.
For some examples requires ASP.NET MVC 3.0.
Installation
Information in this section will be of interest only if you want to use the library in your own projects. The examples should work without any additional actions. If you do not plan to use the library to your projects, just skip this section.
Before you get started, you need add a reference to the library to your project. This can be done in two ways:
- Automatic, through Package Manager Console (recommended)
- Manually add a reference to the assembly
Using the Package Manager Console
To open the Package Manager Console, select menu: Tools => Library Package Manager => Package Manager Console.
In the Package source list, select the NuGet package feed.
To install Nemiro.OAuth
, run the following command in the Package Manager Console:
PM> Install-Package Nemiro.OAuth
Enjoy!
Adding Reference Manually
If you do not have Package Manager or it does not work, you can download Nemiro.OAuth and add a reference to the assembly in your project.
Select menu Project and then click Add Reference....
Select Browse tab, locate and select the Nemiro.OAuth.dll and then click Ok.
Enjoy!
In Windows Forms projects, you may need to change the target version of the .NET Framework.
You must use the full version of the .NET Framework.
If Visual Studio displays an error message: "The type or namespace name 'Nemiro' could not be found", then you should change the target version of the .NET Framework.
To change the target version, select menu Project and then click [Your application name] Properties....
On the Application tab, select the target version of the .NET Framework WITHOUT Client Profile.
Note: If you are using Visual Basic .NET and Visual Studio 2010, then change the target version of the .NET Framework performed on Build tab in section Advanced build options.
Using the Library
First, you need to create an application on the site of provider OAuth. For each provider individually, which you require.
Provider will issue a unique identifier and a secret key for your application. These parameters should be used when initializing the client of provider in your project.
Proper configuration of the application on the provider's website - this is the hardest, with what you have to face.
For web projects, you need to specify the address of a callback. Note that some providers do not work with localhost and/or require the use of the protocol HTTPS. Incorrect configuration a callback address is the most common cause of problems.
You can find detailed instructions in the documentation for the library Nemiro.OAuth
.
The following table presents the list of OAuth providers, their features and direct links to the documentation for each provider:
Provider | Internal name | localhost
supports | Multiple Url
supports | HTTP
supports |
Amazon | amazon | | | |
CodeProject | codeproject | | | |
Dropbox | dropbox | | | |
Facebook | facebook | | | |
Foursquare | foursquare | | | |
GitHub | github | | | |
Google | google | | | |
Instagram | instagram | | | |
LinkedIn | linkedin | | | |
Microsoft Live | live | | | |
Mail.Ru | mail.ru | | | |
Odnoklassniki | odnoklassniki | | | |
SoundCloud | soundcloud | | | |
SourceForge | sourceforge | | | |
Tumblr | tumblr | | | |
Twitter | twitter | | | |
VKontakte | vk | | | |
Yahoo! | yahoo | | | |
Yandex | yandex | | | |
Note: The information in the table is current as of February 2015.
Note: The internal name is case-insensitive.
Note: If the provider supports the localhost, then allowed to use the HTTP protocol for localhost.
HTTP supports field is only for external addresses.
After receiving the access settings for your application, you can register a client for a specific provider in your project.
For convenience, imports namespaces Nemiro.OAuth
and Nemiro.OAuth.Clients
in your code:
using Nemiro.OAuth;
using Nemiro.OAuth.Clients;
Imports Nemiro.OAuth
Imports Nemiro.OAuth.Clients
OAuth client classes are located in the namespace Nemiro.OAuth.Clients
.
You can create an instance of a client OAuth, but you will have to perform all the operations manually. This is not convenient.
Note: As an initialization parameters, you must pass the Application ID and Secret key, which were obtained from the provider.
var twitter = new TwitterClient
(
"cXzSHLUy57C4gTBgMGRDuqQtr",
"3SSldiSb5H4XeEMOIIF4osPWxOy19jrveDcPHaWtHDQqgDYP9P"
);
Dim twitter As New TwitterClient _
(
"cXzSHLUy57C4gTBgMGRDuqQtr",
"3SSldiSb5H4XeEMOIIF4osPWxOy19jrveDcPHaWtHDQqgDYP9P"
)
It is best to use helper classes: OAuthManager
and OAuthWeb
.
For the registration of a client in your application must use method RegisterClient
of the class OAuthManager
.
You can create an instance of a client, or specify the internal name of a provider (the list is presented in the table above).
OAuthManager.RegisterClient
(
new DropboxClient
(
"0le6wsyp3y085wy",
"48afwq9yth83y7u"
)
);
OAuthManager.RegisterClient
(
"LinkedIn",
"75vufylz829iim",
"VOf14z4T1jie4ezS"
);
OAuthManager.RegisterClient _
(
New DropboxClient _
(
"0le6wsyp3y085wy",
"48afwq9yth83y7u"
)
)
OAuthManager.RegisterClient _
(
"LinkedIn",
"75vufylz829iim",
"VOf14z4T1jie4ezS"
)
Note: In the application, you can register only one OAuth client for one provider.
Now with the help of class OAuthWeb
, you can get an address for user authorization on external site.
To do this, use the method GetAuthorizationUrl
, which takes the internal name of the registered provider and also can take an address to which the user will be returned after authorization.
Specifying the callback address is not necessary if you are doing an application for Windows and the provider allows it to do. But in a web project, it is always necessary.
Note: For some providers, the callback address can be specified in the application settings (on the provider site).
string url = OAuthWeb.GetAuthorizationUrl("dropbox");
Dim url As String = OAuthWeb.GetAuthorizationUrl("dropbox")
After returning the user to the return address using the method VerifyAuthorization
of the OAuthWeb
class, you can check the authorization results.
The method VerifyAuthorization
can take the address of the page callback. For web projects explicitly pass the address is not necessary. Default the method is handles current address (Request.Url
).
The method returns an instance of the class AuthorizationResult
, which, if successful, will contain an access token and information of user.
var result = OAuthWeb.VerifyAuthorization("http://the received address from an OAuth provider");
if (result.IsSuccessfully)
{
var user = result.UserInfo;
Console.Write(String.Format("User ID: {0}", user.UserId));
Console.Write(String.Format("Name: {0}", user.DisplayName));
Console.Write(String.Format("Email: {0}", user.Email));
}
else
{
Console.Write(result.ErrorInfo.Message);
}
Dim result = OAuthWeb.VerifyAuthorization("http://the received address from an OAuth provider")
If result.IsSuccessfully Then
Dim user = result.UserInfo
Console.Write(String.Format("User ID: {0}", user.UserId))
Console.Write(String.Format("Name: {0}", user.DisplayName))
Console.Write(String.Format("Email: {0}", user.Email))
Else
Console.Write(result.ErrorInfo.Message)
End If
It's very simple.
Next will be considered in detail the process of implementing the authorization through protocol OAuth in projects ASP.NET WebForms, MVC and Windows Forms.
OAuth Authorization in ASP.NET
Practical implementation of the authorization through OAuth protocol in projects ASP.NET takes just a few easy steps!
- Add to your project the file Global.asax, if they do not exist. Open the Global.asax and add code for registration OAuth clients to the
Application_Start
handler. For example, if you want to implement authorization through Yahoo! and Twitter, you need to register clients: YahooClient
and TwitterClient
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using Nemiro.OAuth;
using Nemiro.OAuth.Clients;
namespace Test.CSharp.AspWebForms
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
OAuthManager.RegisterClient
(
"yahoo",
"dj0yJmk9Qm1vZ3p2TmtQUm4zJmQ9WVdrOU4wbGlkWGxJT" +
"kc4bWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD0xZQ--",
"a55738627652db0acfe464de2d9be13963b0ba1f"
);
OAuthManager.RegisterClient
(
"twitter",
"cXzSHLUy57C4gTBgMGRDuqQtr",
"3SSldiSb5H4XeEMOIIF4osPWxOy19jrveDcPHaWtHDQqgDYP9P"
);
}
}
}
Imports Nemiro.OAuth
Imports Nemiro.OAuth.Clients
Public Class Global_asax
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
OAuthManager.RegisterClient _
(
"yahoo",
"dj0yJmk9Qm1vZ3p2TmtQUm4zJmQ9WVdrOU4wbGlkWGxJT" &
"kc4bWNHbzlNQS0tJnM9Y29uc3VtZXJzZWNyZXQmeD0xZQ--",
"a55738627652db0acfe464de2d9be13963b0ba1f"
)
OAuthManager.RegisterClient _
(
"twitter",
"cXzSHLUy57C4gTBgMGRDuqQtr",
"3SSldiSb5H4XeEMOIIF4osPWxOy19jrveDcPHaWtHDQqgDYP9P"
)
End Sub
End Class
Note: Please use your own Application ID and Secret key for your application, which you get from the provider OAuth. Operability of the access settings presented in this article cannot be guaranteed.
Note: Presented in this article access settings for Yahoo! will not work because the application in Yahoo! linked to a specific hostname. Use your own access settings. And please note, Yahoo! does not support localhost.
- On the pages of your site, place buttons that will redirect the user to an external site for authentication. For example, you can make a
UserControl
, or to place a buttons on a MasterPage
.
Note: It is recommended to use server buttons, because by obtaining authorization addresses in the server memory creates a unique session.
All buttons can have a single click event handler. To distinguish between the buttons, you can add the attribute data-provider
, which will contains the provider name.
<asp:LinkButton ID="lnkFacebook" runat="server" data-provider="yahoo"
Text="Login with Yahoo!" onclick="RedirectToLogin_Click" /><br />
<asp:LinkButton ID="lnkTwitter" runat="server" data-provider="twitter"
Text="Login with Twitter" onclick="RedirectToLogin_Click" />
protected void RedirectToLogin_Click(object sender, EventArgs e)
{
string provider = ((LinkButton)sender).Attributes["data-provider"];
string returnUrl = new Uri(Request.Url, "ExternalLoginResult.aspx").AbsoluteUri;
OAuthWeb.RedirectToAuthorization(provider, returnUrl);
}
Protected Sub RedirectToLogin_Click(sender As Object, e As System.EventArgs)
Dim provider As String = CType(sender, LinkButton).Attributes("data-provider")
Dim returnUrl As String = New Uri(Request.Url, "ExternalLoginResult.aspx").AbsoluteUri
OAuthWeb.RedirectToAuthorization(provider, returnUrl)
End Sub
- Create a new page - ExternalLoginResult.aspx. This page will process the authorization result.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Nemiro.OAuth;
namespace Test.CSharp.AspWebForms
{
public partial class ExternalLoginResult : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var result = OAuthWeb.VerifyAuthorization();
Response.Write(String.Format("Provider: {0}<br />", result.ProviderName));
if (result.IsSuccessfully)
{
var user = result.UserInfo;
Response.Write(String.Format("User ID: {0}<br />", user.UserId));
Response.Write(String.Format("Name: {0}<br />", user.DisplayName));
Response.Write(String.Format("Email: {0}", user.Email));
}
else
{
Response.Write(result.ErrorInfo.Message);
}
}
}
}
Imports Nemiro.OAuth
Public Class ExternalLoginResult
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim result As AuthorizationResult = OAuthWeb.VerifyAuthorization()
Response.Write(String.Format("Provider: {0}<br />", result.ProviderName))
If result.IsSuccessfully Then
Dim user As UserInfo = result.UserInfo
Response.Write(String.Format("User ID: {0}<br />", user.UserId))
Response.Write(String.Format("Name: {0}<br />", user.DisplayName))
Response.Write(String.Format("Email: {0}", user.Email))
Else
Response.Write(result.ErrorInfo.Message)
End If
End Sub
End Class
Enjoy!
ASP.NET MVC
- Add a method
ExternalLogin
to the controller HomeController
. This method will take the provider name and will redirect the user to an external site for authentication.
public ActionResult ExternalLogin(string provider)
{
string returnUrl = Url.Action("ExternalLoginResult", "Home", null, null, Request.Url.Host);
return Redirect(OAuthWeb.GetAuthorizationUrl(provider, returnUrl));
}
Public Function ExternalLogin(provider As String) As ActionResult
Dim returnUrl As String = Url.Action("ExternalLoginResult", "Home", Nothing, Nothing, Request.Url.Host)
Return Redirect(OAuthWeb.GetAuthorizationUrl(provider, returnUrl))
End Function
- Add another method, named
ExternalLoginResult
, which will process the authorization result.
public ActionResult ExternalLoginResult()
{
string output = "";
var result = OAuthWeb.VerifyAuthorization();
output += String.Format("Provider: {0}\r\n", result.ProviderName);
if (result.IsSuccessfully)
{
var user = result.UserInfo;
output += String.Format("User ID: {0}\r\n", user.UserId);
output += String.Format("Name: {0}\r\n", user.DisplayName);
output += String.Format("Email: {0}", user.Email);
}
else
{
output += result.ErrorInfo.Message;
}
return new ContentResult
{
Content = output,
ContentType = "text/plain"
};
}
Public Function ExternalLoginResult() As ActionResult
Dim output As String = ""
Dim result As AuthorizationResult = OAuthWeb.VerifyAuthorization()
output &= String.Format("Provider: {0}", result.ProviderName)
output &= vbCrLf
If result.IsSuccessfully Then
Dim user As UserInfo = result.UserInfo
output &= String.Format("User ID: {0}", user.UserId)
output &= vbCrLf
output &= String.Format("Name: {0}", user.DisplayName)
output &= vbCrLf
output &= String.Format("Email: {0}", user.Email)
Else
output &= result.ErrorInfo.Message
End If
Return New ContentResult() With _
{
.Content = output,
.ContentType = "text/plain"
}
End Function
- And now, just place a links on a page that will trigger the action
ExternalLogin
.
@{string url = Url.Action("ExternalLogin",new { provider="yahoo" });}
<a href="#" onclick="window.location.href='@(url);return false;'">Login with Yahoo!</a>
<br />
@{url = Url.Action("ExternalLogin", new { provider="twitter" });}
<a href="#"
onclick="window.location.href='@(url);return false;'">Login with Twitter</a>
Note: It is recommended to use JavaScript links, because by obtaining authorization addresses in the server memory creates a unique session.
Enjoy!
In Windows Forms projects to implement authentication through OAuth protocol can be using the WebBrowser
control.
You can use ready-to-use forms. To this must be added to the project one more assembly - Nemiro.OAuth.LoginForms
.
To install the library, run the following command in the Package Manager Console:
PM> Install-Package Nemiro.OAuth.LoginForms
Or download and add a reference to the assembly in your project.
The Nemiro.OAuth.LoginForms
library contains classes OAuth providers as forms.
To start using these classes, import the Nemiro.OAuth.LoginForms
in your code:
using Nemiro.OAuth.LoginForms;
Imports Nemiro.OAuth.LoginForms
Using classes is very simple. To get an access token, you must complete all three steps.
- Create a new instance of authorization form of a necessary provider. Use Client ID and Client secret for your application, which you gets from the provider OAuth. For example, login form for Instagram.
var login = new InstagramLogin
(
"9fcad1f7740b4b66ba9a0357eb9b7dda",
"3f04cbf48f194739a10d4911c93dcece",
"http://oauthproxy.nemiro.net/"
);
Dim login As New InstagramLogin _
(
"9fcad1f7740b4b66ba9a0357eb9b7dda",
"3f04cbf48f194739a10d4911c93dcece",
"http://oauthproxy.nemiro.net/"
)
Note: For Instagram requires to specify the callback address.
I made an intermediate gateway for this. This address is specified in the application settings on the site Instagram.
You can use this address for your projects, but there is no guarantee that it will always work.
- Show the form in dialog mode.
login.ShowDialog();
login.ShowDialog()
- After closing the login form, you can check the result of the authorization.
if (login.IsSuccessfully)
{
MessageBox.Show
(
String.Format("Access token: {0}", login.AccessTokenValue),
"Successfully",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
}
If login.IsSuccessfully Then
MessageBox.Show _
(
String.Format("Access token: {0}", login.AccessTokenValue),
"Successfully",
MessageBoxButtons.OK,
MessageBoxIcon.Information
)
End If
Use the access token to work with API.
If desired, you can make your own authorization form.
- In the load event handler of the main form, or application initialization, register the clients OAuth, which you need. For example, if you want to implement authorization through Facebook and Yandex, you need to register clients:
FacebookClient
and YandexClient
.
private void Form1_Load(object sender, EventArgs e)
{
OAuthManager.RegisterClient
(
new FacebookClient
(
"1435890426686808",
"c6057dfae399beee9e8dc46a4182e8fd"
)
{
Parameters = new NameValueCollection { { "display", "popup" } }
}
);
OAuthManager.RegisterClient
(
new YandexClient
(
"0ee5f0bf2cd141a1b194a2b71b0332ce",
"59d76f7c09b54ad38e6b15f792da7a9a"
)
);
}
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
OAuthManager.RegisterClient _
(
New FacebookClient _
(
"1435890426686808",
"c6057dfae399beee9e8dc46a4182e8fd"
) _
With
{
.Parameters = New NameValueCollection() From {{"display", "popup"}}
}
)
OAuthManager.RegisterClient _
(
New YandexClient _
(
"0ee5f0bf2cd141a1b194a2b71b0332ce",
"59d76f7c09b54ad38e6b15f792da7a9a"
)
)
End Sub
- Place two buttons on the form and add a common click handler (
btn_Click
), which will open the login window. In the Tag
property keys must specify the name of the provider OAuth.
private void btn_Click(object sender, EventArgs e)
{
var frm = new frmLogin(((Button)sender).Tag.ToString());
frm.ShowDialog();
}
Private Sub btn_Click(sender As System.Object, e As System.EventArgs)
Call New Form2(CType(sender, Button).Text).ShowDialog()
End Sub
- Add a new form (named
frmLogin
) and place the WebBrowser
control. - Create a constructor for the form
frmLogin
, which takes a single string
argument. When initializing the form, will be formed address for user authentication, which will be set to the WebBrowser
.
public frmLogin(string providerName)
{
InitializeComponent();
webBrowser1.Navigate(OAuthWeb.GetAuthorizationUrl(providerName));
}
Public Sub New(providerName As String)
InitializeComponent()
WebBrowser1.Navigate(OAuthWeb.GetAuthorizationUrl(providerName))
End Sub
- In the event handler
DocumentCompleted
of the WebBrowser
, put code that will search and verify the results of authorization.
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if
(
e.Url.Query.IndexOf("code=") != -1 ||
e.Url.Fragment.IndexOf("code=") != -1 ||
e.Url.Query.IndexOf("oauth_verifier=") != -1
)
{
var result = OAuthWeb.VerifyAuthorization(e.Url.ToString());
if (result.IsSuccessfully)
{
MessageBox.Show
(
String.Format
(
"User ID: {0}\r\nUsername: {1}\r\nDisplay Name: {2}\r\nE-Mail: {3}",
result.UserInfo.UserId,
result.UserInfo.UserName,
result.UserInfo.DisplayName ?? result.UserInfo.FullName,
result.UserInfo.Email
),
"Successfully",
MessageBoxButtons.OK,
MessageBoxIcon.Information
);
}
else
{
MessageBox.Show
(
result.ErrorInfo.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error
);
}
this.Close();
}
}
Private Sub WebBrowser1_DocumentCompleted _
(
sender As System.Object,
e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs
) Handles WebBrowser1.DocumentCompleted
If Not e.Url.Query.IndexOf("code=") = -1 OrElse _
Not e.Url.Fragment.IndexOf("code=") = -1 OrElse _
Not e.Url.Query.IndexOf("oauth_verifier=") = -1 Then
Dim result = OAuthWeb.VerifyAuthorization(e.Url.ToString())
If result.IsSuccessfully Then
Dim displayName As String = result.UserInfo.DisplayName
If String.IsNullOrEmpty(displayName) Then
displayName = result.UserInfo.FullName
End If
MessageBox.Show _
(
String.Format _
(
"User ID: {0}{4}Username: {1}{4}Display Name: {2}{4}E-Mail: {3}",
result.UserInfo.UserId,
result.UserInfo.UserName,
displayName,
result.UserInfo.Email,
vbNewLine
),
"Successfully",
MessageBoxButtons.OK,
MessageBoxIcon.Information
)
Else
MessageBox.Show _
(
result.ErrorInfo.Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error
)
End If
Me.Close()
End If
End Sub
Enjoy!
Using APIs
Each OAuth provider has its own unique API. Unfortunately, there are no uniform rules for work with API. But the library receives information about users via the API, and you can use these methods to implement other requests.
All requests to server are performed using the method ExecuteRequest
of the class OAuthUtility
. This method returns an instance of RequestResult
class.
The RequestResult
class is capable of handling various formats of server responses. No matter what format of response, structured data will be presented as collection. This should simplify the work with a variety of API.
Next will be shown simple examples of working with the API of various sites with using the access token.
Access Token
The access token is required to work with API and is issued at the user's authorization.
The access token can be found in the AccessTokenValue
property of the AuthorizationResult
or the LoginForm
class.
var result = OAuthWeb.VerifyAuthorization();
if (result.IsSuccessfully)
{
Console.WriteLine("Access token: {0}", result.AccessTokenValue);
}
Dim result = OAuthWeb.VerifyAuthorization()
If result.IsSuccessfully Then
Console.WriteLine("Access token: {0}", result.AccessTokenValue)
End If
You can store the access token in file or database.
CodeProject
CodeProject has a good API. As an example, to make a program to view the forums.
This will be an application Windows Forms.
Open the project properties and go to Settings section. Add the AccessTokent
item. In this parameter will be stored the access token.
Next, create and show the authorization form.
var login = new CodeProjectLogin
(
"92mWWELc2DjcL-6tu7L1Py6yllleqSCt",
"YJXrk_Vzz4Ps02GqmaUY-aSLucxh4kfLq6oq0CtiukPfvbzb9yQG69NeDr2yiV9M",
"https://oauthproxy.nemiro.net/"
);
login.Owner = this;
login.ShowDialog();
Dim login As New CodeProjectLogin _
(
"92mWWELc2DjcL-6tu7L1Py6yllleqSCt",
"YJXrk_Vzz4Ps02GqmaUY-aSLucxh4kfLq6oq0CtiukPfvbzb9yQG69NeDr2yiV9M",
"https://oauthproxy.nemiro.net/"
)
login.Owner = Me
login.ShowDialog()
After a successful login, you must save the access token.
if (login.IsSuccessfully)
{
Properties.Settings.Default.AccessToken = login.AccessTokenValue;
Properties.Settings.Default.Save();
}
If login.IsSuccessfully Then
My.Settings.AccessToken = login.AccessTokenValue
My.Settings.Save()
End If
Then, using the access token can obtain a list of messages. That the program does not freeze, it is best to use asynchronous requests.
int forumId = 1650;
OAuthUtility.GetAsync
(
String.Format("https://api.codeproject.com/v1/Forum/{0}/Threads", forumId),
new HttpParameterCollection
{
{ "page", 1 }
},
authorization: new HttpAuthorization(AuthorizationType.Bearer, Properties.Settings.Default.AccessToken),
callback: UpdateList_Result
);
Dim forumId As Integer = 1650
OAuthUtility.GetAsync _
(
String.Format("https://api.codeproject.com/v1/Forum/{0}/Threads", forumId),
New HttpParameterCollection From _
{
New HttpUrlParameter("page", 1)
},
authorization:=New HttpAuthorization(AuthorizationType.Bearer, My.Settings.AccessToken),
callback:=AddressOf UpdateList_Result
)
The server response will be passed to the method UpdateList_Result
. The list of messages can be displayed in the DataGridView
.
The DataGridView
has three columns. Each column contains data binding parameters.
private void UpdateList_Result(RequestResult result)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<RequestResult>(UpdateList_Result), result);
return;
}
dataGridView1.DataSource = result["items"].Select
(
item => new
{
title = item["title"].ToString(),
author = item["authors"].First()["name"].ToString(),
createdDate = Convert.ToDateTime(item["createdDate"])
}
).ToArray();
}
Private Sub UpdateList_Result(result As RequestResult)
If Me.InvokeRequired Then
Me.Invoke(New Action(Of RequestResult)(AddressOf UpdateList_Result), result)
Return
End If
DataGridView1.DataSource = result("items").Select _
(
Function(item)
Return New With _
{
.title = item("title").ToString(),
.author = item("authors").First()("name").ToString(),
.createdDate = Convert.ToDateTime(item("createdDate"))
}
End Function
).ToArray()
End Sub
Of course, in this article, I gave an incomplete description. Nevertheless, working with the API is quite simple and you can make the application shown in the picture below.
You can find the project in the source file. Project is named CodeProjectForumViewer
. Unfortunately, it is only for C#.
Dropbox
Make a file manager for Dropbox is also very simple.
The basic principles are the same for all projects Windows Forms.
- Create and show the authorization form.
var login = new DropboxLogin("4mlpoeq657vuif8", "1whj6c5mxtkns7m");
login.Owner = this;
login.ShowDialog();
Dim login As New DropboxLogin("4mlpoeq657vuif8", "1whj6c5mxtkns7m")
login.Owner = Me
login.ShowDialog()
- Save the access token in the application settings.
if (login.IsSuccessfully)
{
Properties.Settings.Default.AccessToken = login.AccessTokenValue;
Properties.Settings.Default.Save();
}
If login.IsSuccessfully Then
My.Settings.AccessToken = login.AccessTokenValue
My.Settings.Save()
End If
Having access token, you can get a list of files...
OAuthUtility.GetAsync
(
"https://api.dropbox.com/1/metadata/auto/",
new HttpParameterCollection
{
{ "path", "/" },
{ "access_token", Properties.Settings.Default.AccessToken }
},
callback: GetFiles_Result
);
OAuthUtility.GetAsync _
(
"https://api.dropbox.com/1/metadata/auto/",
new HttpParameterCollection From _
{
New HttpUrlParameter("path", "/"),
New HttpUrlParameter("access_token", My.Settings.AccessToken)
},
callback:=AddressOf GetFiles_Result
);
...and display in the ListBox
private void GetFiles_Result(RequestResult result)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<RequestResult>(GetFiles_Result), result);
return;
}
if (result.StatusCode == 200)
{
listBox1.Items.Clear();
listBox1.DisplayMember = "path";
foreach (UniValue file in result["contents"])
{
listBox1.Items.Add(file);
}
}
else
{
if (result["error"].HasValue)
{
MessageBox.Show
(
result["error"].ToString(),
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
else
{
MessageBox.Show(result.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
Private Sub GetFiles_Result(result As RequestResult)
If Me.InvokeRequired Then
Me.Invoke(New Action(Of RequestResult)(AddressOf GetFiles_Result), result)
Return
End If
If result.StatusCode = 200 Then
ListBox1.Items.Clear()
ListBox1.DisplayMember = "path"
For Each file As UniValue In result("contents")
ListBox1.Items.Add(file)
Next
Else
If result["error"].HasValue Then
MessageBox.Show _
(
result("error").ToString(),
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
)
Else
MessageBox.Show(result.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
End If
End Sub
Upload file to Dropbox, you can by the PUT
method, directly from Stream
.
if (openFileDialog1.ShowDialog() != System.Windows.Forms.DialogResult.OK) { return; }
OAuthUtility.PutAsync
(
"https://api-content.dropbox.com/1/files_put/auto/",
new HttpParameterCollection
{
{"access_token", Properties.Settings.Default.AccessToken},
{"path", Path.Combine("/", Path.GetFileName(openFileDialog1.FileName)).Replace("\\", "/")},
{"overwrite", "true"},
{"autorename","true"},
{openFileDialog1.OpenFile()}
},
callback: Upload_Result
);
If Not OpenFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then Return
OAuthUtility.PutAsync _
(
"https://api-content.dropbox.com/1/files_put/auto/",
New HttpParameterCollection From _
{
New HttpUrlParameter("access_token", My.Settings.AccessToken),
New HttpUrlParameter _
(
"path", Path.Combine("/", Path.GetFileName(OpenFileDialog1.FileName)).Replace("\\", "/")
),
New HttpUrlParameter("overwrite", "true"),
New HttpUrlParameter("autorename","true"),
New HttpRequestBody(OpenFileDialog1.OpenFile())
},
callback:=AddressOf Upload_Result
)
To view the entire cycle of the development of the file manager, you can do so in the next video.
The source code of the project, which is shown in the video, you can find in the folder MyDropBox.
In the folder DropboxExample
shows a more complex example.
Unfortunately, it is only for C#.
Twitter is using an obsolete version of the protocol OAuth.
For each request, in addition to the access token required the token secret and sign the request. This is not as simple as one would like.
You can use the class OAuthAuthorization
. The class will automatically sign every request to the API.
You can make a helper method that will return the authorization header for a request.
private string _ConsumerKey = "cXzSHLUy57C4gTBgMGRDuqQtr";
private string _ConsumerSecret = "3SSldiSb5H4XeEMOIIF4osPWxOy19jrveDcPHaWtHDQqgDYP9P";
private OAuthAuthorization GetAuth()
{
var auth = new OAuthAuthorization();
auth.ConsumerKey = _ConsumerKey;
auth.ConsumerSecret = _ConsumerSecret;
auth.SignatureMethod = SignatureMethods.HMACSHA1;
auth.Token = Properties.Settings.Default.AccessToken;
auth.TokenSecret = Properties.Settings.Default.TokenSecret;
return auth;
}
Private _ConsumerKey As String = "cXzSHLUy57C4gTBgMGRDuqQtr"
Private _ConsumerSecret As String = "3SSldiSb5H4XeEMOIIF4osPWxOy19jrveDcPHaWtHDQqgDYP9P"
Private Function GetAuth() As OAuthAuthorization
Dim auth As New OAuthAuthorization()
auth.ConsumerKey = _ConsumerKey
auth.ConsumerSecret = _ConsumerSecret
auth.SignatureMethod = SignatureMethods.HMACSHA1
auth.Token = My.Settings.AccessToken
auth.TokenSecret = My.Settings.TokenSecret
Return auth
End Function
Now you can use this method to send requests to Twitter. For example, you can get a list of tweets.
OAuthUtility.GetAsync
(
"https://api.twitter.com/1.1/statuses/user_timeline.json",
authorization: GetAuth(),
callback: GetTweets_Result
);
OAuthUtility.GetAsync _
(
"https://api.twitter.com/1.1/statuses/user_timeline.json",
authorization:=GetAuth(),
callback:=AddressOf GetTweets_Result
)
If a successful response, the result will be an array of tweets.
private void GetTweets_Result(RequestResult result)
if (this.InvokeRequired)
{
this.Invoke(new Action<RequestResult>(GetTweets_Result), result);
return;
}
if (result.IsSuccessfully)
{
for(int i = 0; i <= result.Count - 1; i++)
{
UniValue item = result[i];
string username = item["user"]["screen_name"].ToString();
DateTime dateCreated = DateTime.ParseExact
(
item["created_at"].ToString(),
"ddd MMM dd HH:mm:ss zzzz yyyy",
CultureInfo.InvariantCulture
);
Console.WriteLine("@{0} / {1}", username, dateCreated);
Console.WriteLine(item["text"]);
Console.WriteLine("------------------------------------------------------");
}
}
else
{
Console.WriteLine(result);
}
}
Private Sub GetTweets_Result(result As RequestResult)
If Me.InvokeRequired Then
Me.Invoke(New Action(Of RequestResult)(AddressOf GetTweets_Result), result)
Return
End If
If result.IsSuccessfully Then
For i As Integer = 0 To result.Count - 1
Dim item As UniValue = result(i)
Dim username As String = item("user")("screen_name")
Dim dateFormat As String = "ddd MMM dd HH:mm:ss zzzz yyyy"
Dim dateCreated As Date
dateCreated = Date.ParseExact(item("created_at"), dateFormat, CultureInfo.InvariantCulture)
Console.WriteLine("@{0} / {1}", username, dateCreated)
Console.WriteLine(item("text"))
Console.WriteLine("------------------------------------------------------")
Next
Else
Console.WriteLine(result)
End If
End Sub
When you publish a new tweet, you may have problems with encodings. To avoid problems, you can specify the content type of multipart/form-data.
var parameters = new HttpParameterCollection();
parameters.AddFormParameter
(
"status",
"Hello, world! Привет, человеки! Hallo Welt! " +
"Hola mundo! Hola, món! Bonjour le monde! Ciao, mondo!" +
"Բարև, աշխարհ! ハロー・ワールド! 你好,世界"
);
OAuthUtility.PostAsync
(
"https://api.twitter.com/1.1/statuses/update.json",
parameters: parameters,
authorization: GetAuth(),
contentType: "multipart/form-data"
);
Dim parameters As New HttpParameterCollection()
parameters.AddFormParameter _
(
"status",
"Hello, world! Привет, человеки! Hallo Welt! " &
"Hola mundo! Hola, món! Bonjour le monde! Ciao, mondo!" &
"Բարև, աշխարհ! ハロー・ワールド! 你好,世界"
)
OAuthUtility.PostAsync _
(
"https://api.twitter.com/1.1/statuses/update.json",
parameters:=parameters,
authorization:=GetAuth(),
contentType:="multipart/form-data"
)
The source code of the project you can find in the folder TwitterExample.VB. Unfortunately, only for Visual Basic .NET.
And More...
Even more simple examples of interaction with different API, you can find in the source code of the demo site, which is located at Test.OAuthWeb folder.
Creating a New OAuth Client
If you need to create a custom client, you can use the base classes: OAuthClient
for OAuth v1.0 and OAuth2Client
for OAuth v2.0.
Recommended to use OAuth v2.0, as it is easier (if the provider supports this version of the protocol).
Create a new class and inherit from the base class.
public class MyClient : OAuth2Client
{
}
Public Class MyClient
Inherits OAuth2Client
End Class
Override the ProviderName
property and specify a unique name for your client.
public override string ProviderName
{
get
{
return "MyClient";
}
}
Public Overrides ReadOnly Property ProviderName As String
Get
Return "MyClient"
End Get
End Property
In the class constructor, specify the base address for authorization and the address for obtaining the access token.
public MyClient(string clientId, string clientSecret) : base
(
"https://example.org/oauth",
"https://example.org/oauth/access_token",
clientId,
clientSecret
) { }
Public Sub New(clientId As String, clientSecret As String)
MyBase.New _
(
"https://example.org/oauth",
"https://example.org/oauth/access_token",
clientId, clientSecret
)
End Sub
And hardest - overriding the GetUserInfo
method.
You need to read the documentation of the provider and find out how you can get information about user.
With the help of class ApiDataMapping
, you can create a new instance of the class UserInfo
and fill it with data obtained from the API provider.
For example, CodeProject returns information about the user in the format JSON.
{
"id": 1,
"userName": "sample string 2",
"displayName": "sample string 3",
"avatar": "sample string 4",
"email": "sample string 5",
}
You can specify which of obtained parameters must be set in the properties of the class UserInfo
.
For example: id
put to the property UserId
, displayName
to the DisplayName
, avatar
to the Userpic
, etc.
var map = new ApiDataMapping();
map.Add("id", "UserId", typeof(string));
map.Add("userName", "UserName");
map.Add("displayName", "DisplayName");
map.Add("email", "Email");
map.Add("avatar", "Userpic");
Dim map As New ApiDataMapping()
map.Add("id", "UserId", GetType(String))
map.Add("userName", "UserName")
map.Add("displayName", "DisplayName")
map.Add("email", "Email")
map.Add("avatar", "Userpic")
If necessary, you can make custom handler of data.
map.Add
(
"displayName", "DisplayName",
delegate(UniValue value)
{
return value.ToString().ToUpper();
}
);
map.Add _
(
"displayName", "DisplayName",
Function(value As UniValue)
Return value.ToString().ToUpper()
End Function
)
If you cannot get information about the user, the GetUserInfo
method may return an empty instance of the class UserInfo
.
return new UserInfo(UniValue.Empty, null);
Return New UserInfo(UniValue.Empty, Nothing)
Using the client exactly as any other.
Epilog
Using authorization through external resources is an important element in the promotion of websites and usability for users.
You can significantly increase user engagement and loyalty, and increase the number of users.
Using an API, you can significantly extend the functionality of your applications.
I hope the Nemiro.OAuth
library will be useful for you and will help ease the integration with a various projects.
The source code of the project is open and you can use it at their own discretion. If you have an account on GitHub, you can to fork the project repository.
History
- 10th February, 2015: First version
- 27th July, 2016: Updated source code and binary files
- 8th August, 2016: Updated source code and binary files