Search code examples
c#google-apigoogle-drive-apigoogle-oauthgoogle-api-dotnet-client

C# Google Drive : Allow users read access to my drive


I just can't seem to be able to find a clear answer to what i want to do.

I have a Google Drive where i maintain a set of folders and files. (Not my private one, but a Drive specifically created for this purpose.) I'm writing a program that will download any folders / files that are changed since the user last checked. The files are in folders that are shared (Anyone with link can view)

How do i go about giving the user (through my program) read access to my Google Drive?

All the OAuth2 / client_secret.json samples i could find allow me to ask permission to the user to access THEIR drive. Which is not what i want.

UserCredential credential;
using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{    
    credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None);
}

_driveService = new DriveService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = ApplicationName
});

FilesResource.ListRequest request = _driveService.Files.List();
FileList files = await request.ExecuteAsync();

I tried using the Api key way, but then i get errors saying the user needs to be logged in.

_driveService = new DriveService(new BaseClientService.Initializer()
{
    ApiKey = "[MyApiKey]",
    ApplicationName = ApplicationName
});

FilesResource.ListRequest request = _driveService.Files.List();
FileList files = await request.ExecuteAsync();

Solution

  • I recomend you look into using a service account. Service accounts are like dummy users. If you grant the service account access to these folders it will have permission to access to do what ever you wish with them. No user will need to login and authenticate the access. Service accounts are pre-authorized.

    Example

    /// <summary>
        /// Authenticating to Google using a Service account
        /// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
        /// </summary>
        /// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
        /// <param name="serviceAccountCredentialFilePath">Location of the .p12 or Json Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
        /// <returns>AnalyticsService used to make requests against the Analytics API</returns>
        public static DriveService AuthenticateServiceAccount(string serviceAccountEmail, string serviceAccountCredentialFilePath, string[] scopes)
        {
            try
            {
                if (string.IsNullOrEmpty(serviceAccountCredentialFilePath))
                    throw new Exception("Path to the service account credentials file is required.");
                if (!File.Exists(serviceAccountCredentialFilePath))
                    throw new Exception("The service account credentials file does not exist at: " + serviceAccountCredentialFilePath);
                if (string.IsNullOrEmpty(serviceAccountEmail))
                    throw new Exception("ServiceAccountEmail is required.");                
    
                // For Json file
                if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".json")
                {
                    GoogleCredential credential;
                    using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
                    {
                        credential = GoogleCredential.FromStream(stream)
                             .CreateScoped(scopes);
                    }
    
                    // Create the  Analytics service.
                    return new DriveService(new BaseClientService.Initializer()
                    {
                        HttpClientInitializer = credential,
                        ApplicationName = "Drive Service account Authentication Sample",
                    });
                }
                else if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".p12")
                {   // If its a P12 file
    
                    var certificate = new X509Certificate2(serviceAccountCredentialFilePath, "notasecret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
                    var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
                    {
                        Scopes = scopes
                    }.FromCertificate(certificate));
    
                    // Create the  Drive service.
                    return new DriveService(new BaseClientService.Initializer()
                    {
                        HttpClientInitializer = credential,
                        ApplicationName = "Drive Authentication Sample",
                    });
                }
                else
                {
                    throw new Exception("Unsupported Service accounts credentials.");
                }
    
            }
            catch (Exception ex)
            {                
                throw new Exception("CreateServiceAccountDriveFailed", ex);
            }
        }
    }
    

    Code ripped from my sample project serviceaccount.cs i also have a post on how service accounts work Google development for beginners service account