{"id":5304,"date":"2016-03-13T17:19:15","date_gmt":"2016-03-13T15:19:15","guid":{"rendered":"https:\/\/www.limilabs.com\/blog\/?p=5304"},"modified":"2022-05-04T14:14:39","modified_gmt":"2022-05-04T12:14:39","slug":"oauth2-gmail-imap-web-applications-dotnetopenauth","status":"publish","type":"post","link":"https:\/\/www.limilabs.com\/blog\/oauth2-gmail-imap-web-applications-dotnetopenauth","title":{"rendered":"OAuth 2.0 with Gmail over IMAP for web applications (DotNetOpenAuth)"},"content":{"rendered":"\n<div class=\"well\">Consider using <a href=\"\/blog\/oauth2-gmail-imap-web-applications\">Google.Apis version for desktop applications<\/a> instead of DotNetOpenAuth version.<\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft\"><img loading=\"lazy\" decoding=\"async\" width=\"131\" height=\"61\" src=\"\/blog\/wp-content\/uploads\/2009\/11\/gmail.png\" alt=\"\" class=\"wp-image-271\" title=\"gmail\"\/><\/figure><\/div>\n\n\n\n<p><strong>OAuth <\/strong> is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.<\/p>\n\n\n\n<p>This article describes using OAuth 2.0 to access Gmail IMAP and SMTP servers using <a href=\"\/mail\">.NET IMAP component<\/a> in web application scenario (ASP.NET\/ASP.NET MVC). You can also use <a href=\"\/blog\/oauth2-gmail-imap-installed-applications\">OAuth 2.0 for installed applications.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">DotNetOpenAuth<\/h2>\n\n\n\n<p>First download the latest version of DotNetOpenAuth &#8211; it&#8217;s free, open source library that implements OAuth 2.0: <a href=\"http:\/\/www.dotnetopenauth.net\">http:\/\/www.dotnetopenauth.net<\/a><\/p>\n\n\n\n<p>Add it as a reference and import namespaces:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/ c#\n\nusing DotNetOpenAuth.OAuth2;\nusing DotNetOpenAuth.OAuth2.Messages;\nusing DotNetOpenAuth.Messaging;\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: vb; title: ; notranslate\" title=\"\">\n' VB.NET \n\nImports DotNetOpenAuth.OAuth2\nImports DotNetOpenAuth.OAuth2.Messages\nImports DotNetOpenAuth.Messaging\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Register Application<\/h2>\n\n\n\n<p>Before you can use OAuth 2.0, you must register your application using the <a href=\"https:\/\/cloud.google.com\/console\" rel=\"nofollow\">Google Developers Console<\/a>. After you&#8217;ve registered, go to the API Access tab and copy the &#8220;<strong>Client ID<\/strong>&#8221; and &#8220;<strong>Client secret<\/strong>&#8221; values and specify &#8220;<strong>Redirect URI<\/strong>&#8220;, which you&#8217;ll need later.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/09\/OAuth2_1a.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>At least product name must be specified:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/09\/OAuth2_1b.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Now create credentials:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/09\/OAuth2_1c.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Specify redirect URI:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/09\/OAuth2_1d_web.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>After you\u2019ve registered, copy the &#8220;<strong>Client ID<\/strong>&#8221; and &#8220;<strong>Client secret<\/strong>&#8221; values, which you\u2019ll need later:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/09\/OAuth2_1e.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>Now we can define clientID, clientSecret, redirect url and scope variables, as well as Google OAuth 2.0 server addresses. Scope basically specifies what services we want to have access to. In our case it is user&#8217;s email address and IMAP\/SMTP access:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nconst string clientID = &quot;12345.apps.googleusercontent.com&quot;;\nconst string clientSecret = &quot;XXXYYY111&quot;;\nconst string redirectUri = &quot;http:\/\/www.yourdomain.com\/oauth2callback&quot;;\n\nAuthorizationServerDescription server = new AuthorizationServerDescription\n    {\n        AuthorizationEndpoint = new Uri(&quot;https:\/\/accounts.google.com\/o\/oauth2\/auth&quot;),\n        TokenEndpoint = new Uri(&quot;https:\/\/oauth2.googleapis.com\/token&quot;),\n        ProtocolVersion = ProtocolVersion.V20,\n    };\nList&lt;string&gt; scope = new List&lt;string&gt;\n    {\n        GoogleScope.ImapAndSmtp.Name,\n        GoogleScope.UserInfoEmailScope.Name\n    };\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Obtain an OAuth 2.0 access token<\/h2>\n\n\n\n<p>As we are using <strong>ASP.NET<\/strong> we&#8217;ll use <em>WebServerClient<\/em> class:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nWebServerClient consumer = new WebServerClient(server, clientID, clientSecret);\n\n\/\/ Here redirect to authorization site occurs\nconsumer.RequestUserAuthorization(scope, new Uri(redirectUri));\n<\/pre><\/div>\n\n\n<p>If you use <strong>ASP.NET MVC<\/strong> the last line is different:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\/\/ Here redirect to authorization site occurs\nOutgoingWebResponse response = consumer.PrepareRequestUserAuthorization(\n    scope, new Uri(redirectUri));\n\nreturn response.AsActionResult();\n<\/pre><\/div>\n\n\n<p>At this point user is redirected to Google to authorize the access:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"\/blog\/wp-content\/uploads\/2012\/09\/OAuth2_2.png\" alt=\"\" title=\"OAuth 2.0 user authorizes the request\"\/><\/figure>\n\n\n\n<p>After this step user is redirected back to your website (http:\/\/www.yourdomain.com\/oauth2callback). Following is this callback code. Its purpose is to get a refresh-token and an access-token:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nWebServerClient consumer= new WebServerClient(server, clientID, clientSecret);\nconsumer.ClientCredentialApplicator =\n    ClientCredentialApplicator.PostParameter(clientSecret);\nIAuthorizationState grantedAccess = consumer.ProcessUserAuthorization(null);\n\nstring accessToken = grantedAccess.AccessToken;\n<\/pre><\/div>\n\n\n<p>An access token is usually valid for a maximum of one hour, and allows you to access the user&#8217;s data. You also received a refresh token. A refresh token can be used to request a new access token once the previous expired.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Access IMAP\/SMTP server<\/h2>\n\n\n\n<p>Finally we&#8217;ll ask Google for user&#8217;s email and use <em>LoginOAUTH2<\/em> method to access Gmail&#8217;s IMAP server:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nGoogleApi api = new GoogleApi(accessToken);\nstring user = api.GetEmail();\n\nusing (Imap imap = new Imap())\n{\n    imap.ConnectSSL(&quot;imap.gmail.com&quot;);\n    imap.LoginOAUTH2(user, accessToken);\n\n    imap.SelectInbox();\n    List&lt;long&gt; uids = imap.Search(Flag.Unseen);\n\n    foreach (long uid in uids)\n    {\n        var eml = imap.GetMessageByUID(uid);\n        IMail email = new MailBuilder().CreateFromEml(eml);\n        Console.WriteLine(email.Subject);\n    }\n    imap.Close();\n}\n<\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">Refreshing access token<\/h2>\n\n\n\n<p>An access token is usually <strong>short lived<\/strong> and valid for a maximum of <strong>one hour<\/strong>. The main reason behind this is security and prevention of replay attacks. This means that for long-lived applications you need to refresh the access token.<\/p>\n\n\n\n<p>In most cases web applications don&#8217;t need to refresh access token (they request new one every time), thus when using <em>WebServerClient<\/em> refresh token is not sent. To force sending refresh token you need to set <code>access_type<\/code> url parameter to <code>offline<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nAuthorizationServerDescription authServer = new AuthorizationServerDescription\n{\n    AuthorizationEndpoint =\n        new Uri(\"https:\/\/accounts.google.com\/o\/oauth2\/auth?access_type=offline\"),\n    ...\n};\n<\/pre><\/div>\n\n\n<p><strong>Your refresh token will be sent only once &#8211; don&#8217;t loose it!<\/strong><\/p>\n\n\n\n<p>We recommend storing entire <em>IAuthorizationState<\/em> object received from <em>WebServerClient.ProcessUserAuthorization<\/em> method call. This object contains both: refresh token and access token, along with its expiration time.<\/p>\n\n\n\n<p>The process of refreshing access token is simple:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nIAuthorizationState grantedAccess = ...\nconsumer.RefreshAuthorization(grantedAccess, TimeSpan.FromMinutes(20));\n<\/pre><\/div>\n\n\n<p>In the example above the access token will not be refreshed if its remaining lifetime exceeds 20 minutes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Retrieving lost refresh token<\/h2>\n\n\n\n<p>When your application receives a refresh token, it is important to store that refresh token for future use. If your application loses the refresh token, it will have to re-prompt the user for consent before obtaining another refresh token.<\/p>\n\n\n\n<p>You&#8217;ll need to add <code>approval_prompt=force<\/code> to your parameters:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nAuthorizationServerDescription authServer = new AuthorizationServerDescription\n {\n     AuthorizationEndpoint =\n          new Uri(\"https:\/\/accounts.google.com\/o\/oauth2\/auth?access_type=offline&approval_prompt=force\"),\n     ...\n };\n<\/pre><\/div>","protected":false},"excerpt":{"rendered":"<p>Consider using Google.Apis version for desktop applications instead of DotNetOpenAuth version. OAuth is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications. This article describes using OAuth 2.0 to access Gmail IMAP and SMTP servers using .NET IMAP component in web application scenario (ASP.NET\/ASP.NET MVC). [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-5304","post","type-post","status-publish","format-standard","hentry","category-news"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/5304"}],"collection":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/comments?post=5304"}],"version-history":[{"count":13,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/5304\/revisions"}],"predecessor-version":[{"id":6206,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/posts\/5304\/revisions\/6206"}],"wp:attachment":[{"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/media?parent=5304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/categories?post=5304"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.limilabs.com\/blog\/wp-json\/wp\/v2\/tags?post=5304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}