andydnd
andydnd

Reputation: 41

How to create Gmail Delegation with Service Account?

We use to create email delegates through Google Email Settings API, but after the deprecation of OAuth 1.0 we were no longer able to authenticate properly. After doing some research I think we should create a service account, delegate domain-wide access for that service account, then authenticate using it. However I can't seem to get it to work, all I receive from Google is 401 unauthorized. Does someone know what I am doing wrong? Here is most of the code, I'm using .Net/c# and I'm using Google Apps for business.

ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer("serviceAccountEmail")
                {
                    Scopes = new[] { "https://apps-apis.google.com/a/feeds/emailsettings/2.0/ " },
                    User = "admin email string"
                }.FromCertificate({X509 certificate from service account p12 file}));

credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(-1);

GoogleMailSettingsService service = new GoogleMailSettingsService("domain name", "appname");
                service.SetAuthenticationToken(credential.Token.AccessToken);

                service.CreateDelegate("delegator", "delegate");

Upvotes: 1

Views: 1225

Answers (2)

andydnd
andydnd

Reputation: 41

For those who may need this answer in the future, I was able to provide a solution through the following. For reference I am running a web app using MVC framework, but the solution could be tweaked for a console or GUI standalone app as well.

Basically, I was able to authenticate the GoogleMailSettingsService.Service.RequestFactory with a GOAuth2RequestFactory object.

For instance:

GoogleMailSettingsService service = new GoogleMailSettingsService("domain", "applicationName");
service.RequestFactory = new GOAuth2RequestFactory("service", "AppName", new OAuth2Parameters() { AccessToken = AuthorizationCodeWebApp.AuthResult.Credential.Token.AccessToken });

Now for the AuthorizationCodeWebApp.AuthResult I implemented the following:

public async Task<ActionResult> DelegationMenu(CancellationToken cancellationToken)
{
        var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);

        if (result.Credential == null)
            return new RedirectResult(result.RedirectUri); //Will redirect to login page for Google Admin to authenticate.

        Session["AuthResult"] = result;
        return View();
}

public class AppFlowMetadata : FlowMetadata
{
    private static readonly IAuthorizationCodeFlow flow =
        new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
        {
            ClientSecrets = new ClientSecrets
            {
                ClientId = "ClientId",
                ClientSecret = "ClientSecret"
            },
            Scopes = new[] { "https://apps-apis.google.com/a/feeds/emailsettings/2.0/" },
            DataStore = new FileDataStore("C:\\OAuth2.0Tokens")
        });

    public override string GetUserId(Controller controller)
    {
        var user = controller.Session["user"];
        if (user == null)
        {
            user = Guid.NewGuid();
            controller.Session["user"] = user;
        }

        return user.ToString();
    }

    public override IAuthorizationCodeFlow Flow
    {
        get { return flow; }
    }
}

Upvotes: 2

miketreacy
miketreacy

Reputation: 1120

A service account isn't required for this action. The Email Settings API, within the Admin SDK, allows a Super Admin to set a delegation for an account within the domain without the need to impersonate the user via a service account.

Check out this section of the Developers site for more information on this API. You can also test this on the OAuth Playground and add delegates right from there.

Upvotes: 0

Related Questions