ACCESS_TOKEN_SCOPE_INSUFFICIENT error with updating sheet using google sheets api (python)

Question:

I’ve been making a program in python that is intended to have each user be able to use it to access a single google sheet and read and update data on it only in the allowed ways, so ive used google api on the google developer console and managed to get test accounts reading the information that ive manually put in, however the update function returns

<HttpError 403 when requesting https://sheets.googleapis.com/v4/spreadsheets/ google sheets id here /values/write%21D1?valueInputOption=RAW&alt=json returned "Request had insufficient authentication scopes.". Details: "[{‘@type’: ‘type.googleapis.com/google.rpc.ErrorInfo’, ‘reason’: ‘ACCESS_TOKEN_SCOPE_INSUFFICIENT’, ‘domain’: ‘googleapis.com’, ‘metadata’: {‘method’: ‘google.apps.sheets.v4.SpreadsheetsService.UpdateValues’, ‘service’: ‘sheets.googleapis.com’}}]">

but the scopes added and used are the ones that relate to what the program does, it has no issue with reading but refuses to update for some reason. I’ve deleted the token.json file and tried updating scopes but it doesn’t seem to want to work.
scopes it currently has is:

non sensitive scopes:

  • Google Sheets API …/auth/drive.file See, edit, create and delete only the specific Google Drive files that you use with this app

sensitive scopes:

  • Google Sheets API …/auth/spreadsheets See, edit, create and delete all your Google Sheets spreadsheets
  • Google Sheets API …/auth/spreadsheets.readonly See all your Google Sheets spreadsheets

there are no restricted scopes.

code here:

from __future__ import print_function

import os.path

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']

# The ID and range of a sample spreadsheet.
spreadID = *redacted for security but this is the correct ID in original code*




def main():
    """Shows basic usage of the Sheets API.
    Prints values from a sample spreadsheet.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        service = build('sheets', 'v4', credentials=creds)

        # Call the Sheets API
        sheet = service.spreadsheets()

        #range used for data reading
        sheetdata_range = 'read!A1:E5' #"pagename!range"
        
        result = sheet.values().get(spreadsheetId=spreadID,
                                    range=sheetdata_range).execute()
        #this is the command that gets the values from the range
        
        
        values = result.get('values', [])

        #print(f"""values variable is:
              #{values}""")

        if not values:#if nothing found it returns this.
            print('No data found.')
            return
        
        for item in values[0]:#for item in row 1
            print(f"values[0] test {item}")
            
        for row in values:#prints items from col 1
            print(row[0])

        rangeupdate = [["1","2","3"],["a","b","c"]]

        request = sheet.values().update(spreadsheetId=spreadID,
                                        range="write!D1",#this is the start point, lists and 2d lists work from this point
                                        valueInputOption="RAW",#how the data is added, this prevents the data being interpreted
                                        body={"values":rangeupdate}).execute()
        print(request)




        
    except HttpError as err:
        print(err)


if __name__ == '__main__':
    main()
Asked By: Doggoluvr

||

Answers:

You are using the sheets.values.update method. If you check the documentation. you will see that this method requires one of the following scopes of authorization

enter image description here

Your code apears to only request 'https://www.googleapis.com/auth/spreadsheets.readonly' read only access is not going to let you write to the file. You need to request the proper scope.

Try https://pygsheets.readthedocs.io/en/stable/

This package may make your life easier.

Answered By: Jatin Morar