Adriano_Pinaffo
Adriano_Pinaffo

Reputation: 1699

C# with Google Drive API: {"Access is denied"}

So, I´m following this Google´s step-by-step for Google Drive API Rest in C#. I basically wanted to list my files in my Google Drive from my console C# application.

I created the Oauth2 credential, downloaded the json file, imported into my Visual Studio project, installed Google Drive APIs v3 using the NuGet manager, copied and pasted the C# code (below). But I keep getting error {"Access is denied"} (in the innerException) in my GoogleWebAuthorizationBroker.AuthorizeAsync() method. Can anyone please help me?

My C# Code:

using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Drive_API_Quickstart__2nd_attempt_
{
    class Program
    {
        // If modifying these scopes, delete your previously saved credentials
        // at ~/.credentials/drive-dotnet-quickstart.json
        static string[] Scopes = { DriveService.Scope.DriveReadonly };
        static string ApplicationName = "Drive API .NET Quickstart";

        static void Main(string[] args)
        {
            UserCredential credential;

            using (var stream =
                new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
            {
                string credPath = System.Environment.GetFolderPath(
                    System.Environment.SpecialFolder.Personal);
                credPath = Path.Combine(credPath, ".credentials/drive-dotnet-quickstart.json");

                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    Scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(credPath, true)).Result;
                Console.WriteLine("Credential file saved to: " + credPath);
            }

            // Create Drive API service.
            var service = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = ApplicationName,
            });

            // Define parameters of request.
            FilesResource.ListRequest listRequest = service.Files.List();
            listRequest.PageSize = 10;
            listRequest.Fields = "nextPageToken, files(id, name)";

            // List files.
            IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute()
                .Files;
            Console.WriteLine("Files:");
            if (files != null && files.Count > 0)
            {
                foreach (var file in files)
                {
                    Console.WriteLine("{0} ({1})", file.Name, file.Id);
                }
            }
            else
            {
                Console.WriteLine("No files found.");
            }
            Console.Read();

        }
    }
}

The debug error:

System.AggregateException was unhandled
  HResult=-2146233088
  Message=One or more errors occurred.
  Source=mscorlib
  StackTrace:
       at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
       at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
       at System.Threading.Tasks.Task`1.get_Result()
       at Drive_API_Quickstart__2nd_attempt_.Program.Main(String[] args) in W:\Adriano\Visual Studio\Google Drive\Drive API Quickstart (2nd attempt)\Drive API Quickstart (2nd attempt)\Program.cs:line 34
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
       ErrorCode=5
       HResult=-2147467259
       Message=Access is denied
       NativeErrorCode=5
       Source=System
       StackTrace:
            at System.Net.HttpListener.AddAllPrefixes()
            at System.Net.HttpListener.Start()
            at Google.Apis.Auth.OAuth2.LocalServerCodeReceiver.StartListener()
            at Google.Apis.Auth.OAuth2.LocalServerCodeReceiver.<ReceiveCodeAsync>d__8.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Google.Apis.Auth.OAuth2.AuthorizationCodeInstalledApp.<AuthorizeAsync>d__8.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.<AuthorizeAsync>d__4.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Google.Apis.Auth.OAuth2.GoogleWebAuthorizationBroker.<AuthorizeAsync>d__1.MoveNext()
       InnerException: 

Upvotes: 1

Views: 3938

Answers (2)

BMJO
BMJO

Reputation: 11

I faced the same issue with a windows desktop program. When I rsn it from the debugger it didn't work. Then I solved the issue by using the "Run as Administrator " option. It popped up with the google account selection window. Here is my code. Make sure you select the auth key properly.

void GoogleThread()
    {
        try
        {
            //Scopes for use with the Google Drive API
            string[] scopes = new string[] { 
                             DriveService.Scope.DriveFile};
            var clientId = "Create auth0 Id and copy here";      // From https://console.developers.google.com
            var clientSecret = "";          // From https://console.developers.google.com

            // here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
            GoogleWebAuthorizationBroker.Folder = "Drive.Sample";
            var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
            {
                ClientId = clientId,
                ClientSecret = clientSecret
            },

            scopes,
            "Admin",
            CancellationToken.None,
            new FileDataStore("Daimto.GoogleDrive.Auth.Store")).Result;

            var service = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Drive API Sample",
            });

            uploadFile(service, "d:\\bmjo\\EastManTemp.xml", "0B1HV_LVO8x0zSWFrRkE2LVFUQ2c");

        }
        catch (Exception exp)
        {
            MessageBox.Show(exp.Message, "Error");
        }
    }
    // tries to figure out the mime type of the file.
    private static string GetMimeType(string fileName)
    {
        string mimeType = "application/unknown";
        string ext = System.IO.Path.GetExtension(fileName).ToLower();
        Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
        if (regKey != null && regKey.GetValue("Content Type") != null)
            mimeType = regKey.GetValue("Content Type").ToString();
        return mimeType;
    }
    public static File uploadFile(DriveService _service, string _uploadFile, string _parent)
    {

        if (System.IO.File.Exists(_uploadFile))
        {
            File body = new File();

            body.Title = System.IO.Path.GetFileName(_uploadFile);
            body.Description = "File uploaded by Diamto Drive Sample";
            body.MimeType = GetMimeType(_uploadFile);
            body.Parents = new List<ParentReference>();// { new ParentReference() { Id = _parent } };
            body.Parents.Add(new ParentReference() { Id = _parent });
            // File's content.
            byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
            System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
            try
            {
                FilesResource.InsertMediaUpload request = _service.Files.Insert(body, stream, GetMimeType(_uploadFile));
                request.Upload();
                return request.ResponseBody;
            }
            catch (Exception e)
            {
                Console.WriteLine("An error occurred: " + e.Message);
                return null;
            }
        }
        else
        {
            Console.WriteLine("File does not exist: " + _uploadFile);
            return null;
        }

    }
    private void button1_Click(object sender, EventArgs e)
    {
        Thread thread = new Thread(new ThreadStart(GoogleThread));
        thread.Start();

    }

Upvotes: 1

Danee
Danee

Reputation: 322

Have you tried this implementing authorization correctly?

The document quickstart that you mentioned has some notes regarding auth:

Notes

Authorization information is stored on the file system, so subsequent executions will not prompt for authorization. The authorization flow in this example is designed for a command-line application. For information on how to perform authorization in a web application, see the web applications section of the library's OAuth 2.0 guide.

Also, kindly follow the steps on what this document about OAuth :

To find the redirect URIs for your OAuth 2.0 credentials, do the following:

1.) Open the Credentials page in the API Console.

2.) If you haven't done so already, create your OAuth 2.0 credentials by clicking Create credentials > OAuth client ID.

3.) After you create your credentials, view or edit the redirect URLs by clicking the client ID (for a web application) in the OAuth 2.0 client IDs section.

You might be missing those steps. You also might have the incorrect file for the client_secrets.json. May I ask if how did you actually downloaded the file?

Upvotes: 1

Related Questions