OAuth 2.0 with Gmail over IMAP for installed applications

You can also read how to use:

 

OAuth 2.0 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 installed applications scenario. You can also use OAuth 2.0 for web applications.

Google.Apis

Use Nuget to download “Google.Apis.Auth” package.

Import namespaces:

// c#

using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;

using Limilabs.Client.Authentication.Google;

using Limilabs.Client.IMAP;
' VB.NET 

Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Auth.OAuth2.Flows
Imports Google.Apis.Auth.OAuth2.Requests
Imports Google.Apis.Auth.OAuth2.Responses

Imports Limilabs.Client.Authentication.Google

Imports Limilabs.Client.IMAP

Register Application

Before you can use OAuth 2.0, you must register your application using the Google Cloud Console. After you’ve registered copy the “Client ID” and “Client secret” values which you’ll need later.

At least product name must be specified:

Now create credentials:

After you’ve registered, copy the “Client ID” and “Client secret” values, which you’ll need later:

Now we can define clientID, clientSecret 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’s email address and IMAP/SMTP access:

// C#

string clientID = "XXX.apps.googleusercontent.com";
string clientSecret = "IxBs0g5sdaSDUz4Ea7Ix-Ua";

var clientSecrets = new ClientSecrets
{
    ClientId = clientID,
    ClientSecret = clientSecret
};

var credential = new GoogleAuthorizationCodeFlow(
    new GoogleAuthorizationCodeFlow.Initializer
    {
        ClientSecrets = clientSecrets,
        Scopes = new[] { 
            GoogleScope.ImapAndSmtp.Name, 
            GoogleScope.UserInfoEmailScope.Name}
    });
' VB.NET 

Dim clientID As String = "XXX.apps.googleusercontent.com"
Dim clientSecret As String = "IxBs0g5sdaSDUz4Ea7Ix-Ua"

Dim clientSecrets = New ClientSecrets With { _
	.ClientId = clientID, _
	.ClientSecret = clientSecret _
}

Dim credential = New GoogleAuthorizationCodeFlow( _
    New GoogleAuthorizationCodeFlow.Initializer With { _
    	.ClientSecrets = clientSecrets, _
	    .Scopes = { _
            GoogleScope.ImapAndSmtp.Name,  _
            GoogleScope.UserInfoEmailScope.Name} _
})

Obtain an OAuth 2.0 access token

Now we’ll create authorization url.

As OOB addresses are no longer supported, to receive the authorization code using this URL, your application must be listening on the local web server. This is the recommended mechanism for obtaining the authorization code.

When your app receives the authorization response, for best usability it should respond by displaying an HTML page that instructs the user to close the browser and return to your app.

Your application needs to create a server that listens on this local address:

http://127.0.0.1:port or http://[::1]:port or http://localhost:port

Query your platform for the relevant loopback IP address and start an HTTP listener on a random available port. Substitute port with the actual port number your app listens on.

// C#

AuthorizationCodeRequestUrl url = credential
    .CreateAuthorizationCodeRequest("http://127.0.0.1:1234/auth2callback");

Process.Start(url.Build().ToString());
' VB.NET 

Dim url As AuthorizationCodeRequestUrl = credential _
    .CreateAuthorizationCodeRequest("http://127.0.0.1:1234/auth2callback")

Process.Start(url.Build().ToString())

We are using Process.Start here, but you can also embed WebBrowser control in your application.

At this point user is redirected to Google to authorize the access:

After this step user is redirected to the loopback address you provided.

Your application’s local web server, listening on this address, should obtain code from the url parameter.

Following is a code that reads this code and contacts Google to exchange it for a refresh-token and an access-token:

string authCode = "get from the url";

TokenResponse token = await credential.ExchangeCodeForTokenAsync(
    "", 
    authCode, 
    "http://127.0.0.1/auth2callback", 
    CancellationToken.None);

string accessToken = token.AccessToken;
' VB.NET 

Dim authCode As String = "get from the url";

Dim token As TokenResponse = Await credential.ExchangeCodeForTokenAsync( _
    "",  _
    authCode,  _
    "http://127.0.0.1/auth2callback",  _
    CancellationToken.None)

Dim accessToken As String = token.AccessToken

An access token is usually valid for a maximum of one hour, and allows you to access the user’s data. You also received a refresh token. A refresh token can be used to request a new access token once the previous expired.

Access IMAP/SMTP server

Finally we’ll ask Google for user’s email and use LoginOAUTH2 method to access Gmail’s IMAP server:

// C#

GoogleApi api = new GoogleApi(accessToken);
string user = api.GetEmail();

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.LoginOAUTH2(user, accessToken);

    imap.SelectInbox();
    List<long> uids = imap.Search(Flag.Unseen);

    foreach (long uid in uids)
    {
        var eml = imap.GetMessageByUID(uid);
        IMail email = new MailBuilder().CreateFromEml(eml);
        Console.WriteLine(email.Subject);
    }
    imap.Close();
}
' VB.NET 

Dim api As New GoogleApi(accessToken)
Dim user As String = api.GetEmail()

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.LoginOAUTH2(user, accessToken)

	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search(Flag.Unseen)

	For Each uid As Long In uids
		Dim eml = imap.GetMessageByUID(uid)
		Dim email As IMail = New MailBuilder().CreateFromEml(eml)
		Console.WriteLine(email.Subject)
	Next
	imap.Close()
End Using

Refreshing access token

An access token is usually short lived and valid for a maximum of one hour. 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.

Your refresh token will be sent only once – don’t loose it!

We recommend storing entire TokenResponse object received from GoogleAuthorizationCodeFlow.ExchangeCodeForTokenAsync method call. This object contains both: refresh token and access token, along with its expiration time.

The process of refreshing access token is simple:

// c#

TokenResponse refreshed = await credential.RefreshTokenAsync(
    "", 
    token.RefreshToken, 
    CancellationToken.None);
' VB.NET 

Dim refreshed As TokenResponse = Await credential.RefreshTokenAsync( _
    "",  _
    token.RefreshToken,  _
    CancellationToken.None)

Tags:       

Questions?

Consider using our Q&A forum for asking questions.