Python脚本调用Gmail API报错:web类型客户端缺失redirect_uris
oauth2client.clientsecrets.InvalidClientSecretsError: Missing property "redirect_uris" for Gmail Scripts Hey there, let's unpack what's happening with your Gmail script and that pesky error.
First, let's get to the root of the issue: Google's OAuth2 framework requires the redirect_uris field for "Web application" type client IDs. This isn't a random quirk of the oauth2client library—it's part of the official OAuth2 spec for web apps, which rely on redirects to complete the authorization flow.
Why your script worked before
Chances are, your original client_secret.json was tied to a Desktop app type client ID (not a Web application). Desktop/script-based apps have different OAuth2 rules—they don't need a custom redirect URI (Google uses a default value like urn:ietf:wg:oauth:2.0:oob for terminal-based auth) and the oauth2client library doesn't enforce the redirect_uris field for this type.
Possible reasons it broke now:
- You might have recreated your client ID in Google Cloud Console and accidentally selected "Web application" instead of "Desktop app".
- You updated the
oauth2clientlibrary to a newer version that enforces stricter validation of client secret fields for Web app types.
How to fix this
You have two solid options:
Option 1: Switch to a Desktop app client ID (recommended for local scripts)
This is the cleanest fix since you don't need redirects for a local script:
- Go to your Google Cloud Console Credentials page
- Either delete your existing "Web application" client ID or create a new one
- Create a new OAuth client ID, select Desktop app as the application type
- Download the new
client_secret.jsonand replace your current file - Your script should work as it did before—no need to add
redirect_urisat all
Option 2: Keep using Web app type (if you have to)
If you must stick with a Web app client ID, you need to keep the redirect_uris field in your client_secret.json—even if you don't actively use the redirect. You can use a placeholder valid for local testing:
{ "web": { "client_id": "your-client-id", "client_secret": "your-client-secret", "redirect_uris": ["http://localhost:8000"], "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token" } }
The library just needs this field to exist and have a valid URI format—you don't need to run a server at that localhost address for a simple send-only script.
Quick code check
Make sure your flow initialization aligns with the client type. For Desktop apps, the standard setup looks like this:
from oauth2client import client, tools from oauth2client.file import Storage CLIENT_SECRET_FILE = 'client_secret.json' SCOPES = ['https://www.googleapis.com/auth/gmail.send'] def get_credentials(): storage = Storage('gmail-token.json') credentials = storage.get() if not credentials or credentials.invalid: flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES) credentials = tools.run_flow(flow, storage) return credentials
This will handle the authorization flow in your terminal (or pop up a browser window) without needing a redirect server.
内容的提问来源于stack exchange,提问作者codyc4321

