pythongoogle-apps-scriptoauth-2.0web-applicationshttp-status-code-401

401 Unauthorized Error when Making POST Request to Google Apps Script Web App with Valid OAuth Token"


I am trying to send a POST request to a Google Apps Script web app using a Python script. While accessing the web app's URL in a web browser works fine with GET requests, sending a POST request with Python results in a 401 Unauthorized error.

The authentication process is as follows:

from google_auth_oauthlib.flow import InstalledAppFlow

SCOPES = ['openid', 'https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/script.webapp.deploy']
CLIENT_SECRETS_FILE = 'client_secret.json'

flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES, redirect_uri='http://localhost:80/')
credentials = flow.run_local_server(port=80)

headers = {
    'Authorization': f'Bearer {credentials.token}',
    'Content-Type': 'application/json',
}

# Checking token validity
if credentials.valid:
    print("Token is valid.")
else:
    print("Token is not valid.")

# Checking if the token has expired
if credentials.expired:
    print("Token has expired.")
else:
    print("Token is still valid.")

print("Scopes granted to the token:", credentials.scopes)
print("Access token:", credentials.token)


    try:
       response = requests.post(url, headers=headers, json={"text": "hello from python with OAuth"})
       response.text
       response.raise_for_status()  # 400 or 500 Error
    except requests.exceptions.HTTPError as err:
        print(f"HTTP error occurred: {err}")  # HTTP Error
    except Exception as err:
        print(f"An error occurred: {err}")  # Other Error 

And the appsscript.json settings for the Apps Script web app are as follows:

{
  "timeZone": "Asia/Seoul",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "webapp": {
    "executeAs": "USER_ACCESSING",
    "access": "DOMAIN"
  }
}

The token is valid, and there are no issues with the granted scopes. According to the Google Cloud Console, the user has owner permissions, and the Apps Script API is enabled.

Despite these settings and conditions, I can't understand why the POST request is failing. The web app's doPost function is configured to handle JSON type POST data. I would appreciate any advice on what I might be missing.

Thank you.

What I Tried:

I sent a POST request to a Google Apps Script web app using a Python script. I authenticated using OAuth 2.0, included the access token in the header, and sent the request. The doPost function in Google Apps Script was set up to receive and process JSON data.

What I Expected:

Having successfully completed the authentication process and obtained a valid access token, I expected the web app to receive the POST request and respond appropriately.

What Actually Happened:

While accessing the web app via a web browser with a GET request works fine, sending a POST request via the Python script results in a 401 Unauthorized error. Consequently, the web app is not processing the request.


Solution

  • About the status code 401, it means The HyperText Transfer Protocol (HTTP) 401 Unauthorized response status code indicates that the client request has not been completed because it lacks valid authentication credentials for the requested resource.. Ref

    In order to request Web Apps with the access token, in the current stage, the scope of Drive API is required to be included. I guessed that when I saw your showing script, this might be due to the reason for your current issue. So, how about the following modification?

    From:

    SCOPES = ['openid', 'https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/script.webapp.deploy']
    

    To:

    SCOPES = ["https://www.googleapis.com/auth/drive"]
    

    or

    SCOPES = ["https://www.googleapis.com/auth/drive.readonly"]
    

    or, if you are required to use the scopes of 'openid', 'https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/script.webapp.deploy', please modify as follows.

    SCOPES = ["https://www.googleapis.com/auth/drive", 'openid', 'https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/script.webapp.deploy']
    

    or

    SCOPES = ["https://www.googleapis.com/auth/drive.readonly", 'openid', 'https://www.googleapis.com/auth/script.projects', 'https://www.googleapis.com/auth/script.webapp.deploy']
    

    Note:

    Reference: