Search code examples
google-apisingle-sign-onopenidazure-active-directorygoogle-api-dotnet-client

How to access Google API in combination with Azure AD single-sign on


I have a web application running on Azure. The web application authenticates the users via OpenID Connect from a Azure Active Directory tenant. Azure Sample on GitHub.

On the Azure Active Directory tenant I have integrated Google Apps and configured single sing-on to Google Apps and automated user provisioning. Tutorial: How to integrate Google Apps with Azure Active Directory.

In my web application I would like to access user content from Google Apps (e.g. files on Google Drive) of the signed in user via Google API.

Is it possible to do this with the help of the setup single sign-on federation, so that the user only needs to sign in to the web application/Azure AD and for the Web API call there is no need for a further sign in, e.g. by using a token optained by Azure AD for accessing the Google Web API?


Solution

  • I ended up with two solutions:

    a) Service Account:
    Accessing the users data with a service account on behalf of a user. For this you have to setup a service account: Using OAuth 2.0 for Server to Server Applications

    private static ServiceAccountCredential GetServiceAccountCredential(string user)
    {
      const string privateKey = "<PRIVATEKEY>";
    
      ServiceAccountCredential credential = new ServiceAccountCredential(
        new ServiceAccountCredential.Initializer("<SERVICEACOUNTEMAIL>")
          {
            Scopes = new[] {DriveService.Scope.Drive},
            User = user
          }.FromPrivateKey(privateKey));
    
      return credential;
    }
    

    b) User: Accessing the users data with the user. For this you have to register your app to get the client ID and secret: Using OAuth 2.0 for Web Server Applications

    private static UserCredential GetUserCredential(string user)
    {
      ClientSecrets secrets = new ClientSecrets
        {
          ClientId = "<CLIENTID>",
          ClientSecret = "<CLIENTSECRET>"
        };
    
      IDataStore credentialPersistanceStore = new FileDataStore("Drive.Sample.Credentials");
    
      Task<UserCredential> result = GoogleWebAuthorizationBroker.AuthorizeAsync(
        secrets, 
        new[] {DriveService.Scope.Drive}, 
        user, 
        CancellationToken.None, 
        credentialPersistanceStore);
    
       result.Wait();
       UserCredential credential = result.Result;
    
       return credential;
     }
    

    With the credentials I can request the files from Drive:

    Claim emailClaim = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
    IConfigurableHttpClientInitializer credential = GetServiceAccountCredential(emailClaim.Value);
    //IConfigurableHttpClientInitializer credential = GetUserCredential(emailClaim.Value);
    
    var service = new DriveService(new BaseClientService.Initializer
      {
        HttpClientInitializer = credential,
        ApplicationName = "My App"
      });
    
    FileList list = service.Files.List().Execute();
    

    I am not yet sure which option I will use. Maybe you have some advices or suggestions.