title: Using google api to create and share a spreadsheet
body: <p>I have a script that I'm attempting to pass data through that would create a google spreadsheet and share it with a group of people. I'm having trouble with an error that is rejecting my permissions, though I don't know why.</p>
  
  <p>I've gone through the google developer console and created a project and enabled both the spreadsheets api and the drive api. I downloaded a single oauth2 set of credentials and named it "credentials.json" </p>
  
  <p>From there I wrote this script based off the google api examples using the v4 sheets and v3 drive versions:</p>
  
  <pre><code>from googleapiclient.discovery import build
  from httplib2 import Http
  from oauth2client import file, client, tools
  
  SCOPES = ['https://www.googleapis.com/auth/drive',
            'https://www.googleapis.com/auth/spreadsheets']
  CREDENTIALS = r'google_api\credentials.json'
  TEST_ADD_EMAIL = &lt;the test gmail address&gt;
  
  class GoogleManager:
      def __init__(self):
          self.sheets_service = None
          self.drive_service = None
  
      def connect(self):
          store = file.Storage(r'google_api\token.json')
          creds = store.get()
  
          if not creds or creds.invalid:
              flow = client.flow_from_clientsecrets(CREDENTIALS, SCOPES)
              creds = tools.run_flow(flow, store)
  
          self.sheets_service = build('sheets', 'v4', http=creds.authorize(Http()))
          self.drive_service = build('drive', 'v3', http=creds.authorize(Http()))
  
      def drive_add_writer_perm(self, fileId, emails):
          def callback(request_id, response, exception):
              if exception:
                  raise exception
              else:
                  print(f"Permission Id: {response.get('id')}")
  
          if isinstance(emails, str):
              emails = [emails]
          elif not isinstance(emails, (list,tuple)):
              raise TypeError('Emails must be str or list-like object')
  
          batch = self.drive_service.new_batch_http_request(callback=callback)
          for email in emails:
              user_permission = ({'type': 'user',
                                  'role': 'writer',
                                  'emailAddress': email
                                  })
              batch.add(self.drive_service.permissions().create(fileId=fileId,
                                                        body=user_permission,
                                                        fields='id'))
          res = batch.execute()
          return res
  
      def create_new_sheet(self, workbook_name):
          spreadsheet = {'properties': {'title': workbook_name}
                         }
          gSheet = self.sheets_service.spreadsheets()
          newsheet = gSheet.create(body=spreadsheet, fields='spreadsheetId').execute()
          return newsheet
  </code></pre>
  
  <p>From there I run: </p>
  
  <pre><code>gmanager = GoogleManager()
  gmanager.connect()
  
  new_sheet = gmanager.create_new_sheet('Test Sheet')
  
  sheet_id = new_sheet.get('spreadsheetId')
  gmanager.drive_add_writer_perm(sheet_id, TEST_ADD_EMAIL)
  </code></pre>
  
  <p>But I get this error:</p>
  
  <pre><code>raise HttpError(resp, content, uri=request.uri).errors.HttpError: &lt;HttpError 403 when requesting https://www.googleapis.com/drive/v3/files/1PuxZR0Cx2tGi7c1worVc_Ivj9kZijq_xwwndix6I9as/permissions?fields=id&amp;alt=json returned "Insufficient Permission"&gt;
  </code></pre>
  
  <p>Can anyone explain why? What am I doing wrong? </p>
  
  <p>edit: when I go to that link in the exception I'm given this response:</p>
  
  <pre><code>{
   "error": {
    "errors": [
     {
      "domain": "global",
      "reason": "required",
      "message": "Login Required",
      "locationType": "header",
      "location": "Authorization"
     }
    ],
    "code": 401,
    "message": "Login Required"
   }
  }
  </code></pre>
  
  <p>I'm not getting a login screen, what is going on?</p>