Search code examples
.netoauth-2.0gmail-imapgoogle-api-dotnet-client

Access Gmail's IMAP using AssertionFlowClient and service account


Is it possible to use AssertionFlowClient and service account to access mailbox of any user in my domain through IMAP. Same as with 2-legged OAuth 1.0.

Here's my code:

X509Certificate2 certificate =  new X509Certificate2(...)
AuthorizationServerDescription server = new AuthorizationServerDescription {...};
List<string> scope = new List<string> { 
    "https://mail.google.com/", 
    "https://www.googleapis.com/auth/userinfo#email" };

AssertionFlowClient provider = new AssertionFlowClient(server, certificate)
{
  ServiceAccountId = SERVICE_ACCOUNT_EMAIL,
  Scope = string.Join(" ",scope.ToArray()),
};

IAuthorizationState grantedAccess = AssertionFlowClient.GetState(provider);
accessToken = grantedAccess.AccessToken;

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

I'm able to retrieve valid accessToken from accounts.google.com server (although AssertionFlowClient/DotNetOpenAuth has a bug and currently I use debugger and watch window to retrieve it).

I'm sure that accessToken is correct, as I can query www.googleapis.com/userinfo/email API endpoint using it - it returns the same value as SERVICE_ACCOUNT_EMAIL.

Gmail's IMAP server returns the following error however:

{"status":"400","schemes":"Bearer","scope":"https://mail.google.com/"}

"Manage API client access" for this service account is configured to "Email (Read/Write/Send) https://mail.google.com/" on cpanel.

AssertionFlowClient/DotNetOpenAuth bug indicates that no-one has ever tried this.

Is it possible at all?


Solution

  • So it seems Google forgot to include this little detail in their documentation:

    AssertionFlowClient provider = new AssertionFlowClient(server, certificate)
        {
            ServiceAccountId = SERVICE_ACCOUNT_EMAIL,
            Scope = "https://mail.google.com/",
            ServiceAccountUser = "user@mydomain.com",  // <- important
        };
    

    It also seems that requesting access to multiple scopes (space separated) fails.