Appearance
OAuth Integration
Universal API provides built-in OAuth support for Google services. This guide explains how to connect your Google account and use OAuth tokens in your actions.
Supported Providers
| Provider | Services | Status |
|---|---|---|
| Gmail, Drive, Calendar, Sheets | Available | |
| Microsoft | Office 365, OneDrive | Coming soon |
| GitHub | Repos, Issues, PRs | Coming soon |
Connecting Your Google Account
Via Web UI
- Go to universalapi.co/keys
- Click "Connect Google Account"
- Select the scopes you need:
- Gmail (send/read emails)
- Drive (file access)
- Calendar (event management)
- Complete the OAuth flow
- Your tokens are securely stored
Via API
bash
# Initiate OAuth flow
curl "https://api.universalapi.co/oauth/google/authorize?userId=your-user-id&redirect_uri=https://universalapi.co/oauth/callback"This returns a URL to redirect the user to Google's consent screen.
Using OAuth in Actions
Check for Tokens
Always verify the user has connected their account:
python
def handler(event, context):
if "keys" not in event or "google_oauth" not in event["keys"]:
return {
"statusCode": 400,
"body": {
"error": "Google account not connected. Please connect at universalapi.co/keys"
}
}
# Continue with OAuth token
google_oauth = event["keys"]["google_oauth"]
access_token = google_oauth["keyValue"]Token Structure
When Google OAuth is connected, your action receives:
python
event["keys"]["google_oauth"] = {
"keyName": "google_oauth",
"keyValue": "ya29.xxx...", # Access token
"secretKeyName": "refresh_token",
"secretKeyValue": "1//0xxx...", # Refresh token
"additionalFields": {
"token_type": "Bearer",
"expires_at": 1736784000000,
"scope": "https://www.googleapis.com/auth/drive https://mail.google.com/"
}
}Automatic Token Refresh
Universal API automatically refreshes tokens when they're about to expire (within 5 minutes). Your action always receives a valid access token.
Example: List Google Drive Files
python
import requests
def handler(event, context):
# Check for OAuth
if "keys" not in event or "google_oauth" not in event["keys"]:
return {
"statusCode": 400,
"body": {"error": "Please connect your Google account"}
}
# Get token
access_token = event["keys"]["google_oauth"]["keyValue"]
# Get parameters
params = event.get("queryStringParameters", {}) or {}
max_results = int(params.get("max_results", 10))
query = params.get("query", "")
# Call Google Drive API
response = requests.get(
"https://www.googleapis.com/drive/v3/files",
headers={"Authorization": f"Bearer {access_token}"},
params={
"pageSize": max_results,
"q": query,
"fields": "files(id,name,mimeType,webViewLink,modifiedTime)"
}
)
if response.status_code != 200:
return {
"statusCode": response.status_code,
"body": {"error": response.text}
}
return {
"statusCode": 200,
"body": {
"files": response.json().get("files", []),
"count": len(response.json().get("files", []))
}
}Example: Send Gmail Email
python
import requests
import base64
from email.mime.text import MIMEText
def handler(event, context):
# Check for OAuth
if "keys" not in event or "google_oauth" not in event["keys"]:
return {
"statusCode": 400,
"body": {"error": "Please connect your Google account"}
}
# Get parameters
params = event.get("queryStringParameters", {}) or {}
to = params.get("to")
subject = params.get("subject")
body = params.get("body")
if not all([to, subject, body]):
return {
"statusCode": 400,
"body": {"error": "Missing required parameters: to, subject, body"}
}
# Get token
access_token = event["keys"]["google_oauth"]["keyValue"]
# Create email
message = MIMEText(body)
message["to"] = to
message["subject"] = subject
raw = base64.urlsafe_b64encode(message.as_bytes()).decode()
# Send via Gmail API
response = requests.post(
"https://gmail.googleapis.com/gmail/v1/users/me/messages/send",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
json={"raw": raw}
)
if response.status_code != 200:
return {
"statusCode": response.status_code,
"body": {"error": response.text}
}
return {
"statusCode": 200,
"body": {
"success": True,
"messageId": response.json().get("id")
}
}OAuth Endpoints
Refresh Token Manually
bash
POST /oauth/google/refreshjson
{
"refreshToken": "1//0xxx..."
}Revoke Token
bash
POST /oauth/google/revokejson
{
"token": "ya29.xxx..."
}Specifying Required Keys
When creating an action that requires OAuth, specify it in keysNeeded:
json
{
"actionName": "List Drive Files",
"keysNeeded": [
{
"name": "google_oauth",
"description": "Google OAuth token with Drive API access"
}
],
"sourceCode": "..."
}This helps users understand what credentials are needed before running the action.
Google OAuth Scopes
| Scope | Permission |
|---|---|
https://www.googleapis.com/auth/drive | Full Drive access |
https://www.googleapis.com/auth/drive.readonly | Read-only Drive |
https://mail.google.com/ | Full Gmail access |
https://www.googleapis.com/auth/gmail.send | Send emails only |
https://www.googleapis.com/auth/calendar | Full Calendar access |
Error Handling
python
def handler(event, context):
if "keys" not in event or "google_oauth" not in event["keys"]:
return {
"statusCode": 401,
"body": {
"error": "OAUTH_NOT_CONNECTED",
"message": "Please connect your Google account at universalapi.co/keys",
"authUrl": "https://universalapi.co/keys"
}
}
try:
# Make API call
response = requests.get(...)
if response.status_code == 401:
return {
"statusCode": 401,
"body": {
"error": "OAUTH_TOKEN_EXPIRED",
"message": "Please reconnect your Google account"
}
}
return {"statusCode": 200, "body": response.json()}
except Exception as e:
return {
"statusCode": 500,
"body": {"error": str(e)}
}Next Steps
- Creating Actions - Build actions with OAuth
- Examples - More OAuth examples
- Keys API - Manage API keys and OAuth