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() 

Answer: 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  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.