You're absolutely right — Google Service Accounts cannot directly upload videos to YouTube via the YouTube Data API because:
YouTube requires access to a real user’s channel, and
Service accounts do not have YouTube channels associated with them.
❗️Why Service Accounts Don’t Work for YouTube Uploads
Service accounts are designed for server-to-server API access. But YouTube APIs require a YouTube channel, and only Google user accounts can own channels. There's no domain-wide delegation workaround because YouTube is not part of Google Workspace-supported services for that feature.
✅ Recommended Workaround (by YouTube API team & community)
Use a regular Google account (with a YouTube channel) and perform an OAuth 2.0 flow once manually, then store and reuse the refresh token on your backend.
🧰 Implementation Steps
1. Create OAuth 2.0 Client in google Cloud Console
Go to: https://console.cloud.google.com/apis/credentials
Create an OAuth 2.0 Client ID
Type: Desktop App or Web App
Enable the YouTube Data API v3
2. Request OAuth Consent
Scopes required:
https://www.googleapis.com/auth/youtube.upload
https://www.googleapis.com/auth/youtube
Run a manual OAuth flow (use Google’s OAuth Playground or your own app)
Get the refresh token and save it securely (DB, encrypted file)
3. Use the Refresh Token on Server
Use a library like google-auth-library (Node.js), google-auth (Python), or equivalent to:
Load client ID/secret and refresh token
Exchange for access token
Call the YouTube Data API to upload video
//python code
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
creds = Credentials(
None,
refresh_token="YOUR_REFRESH_TOKEN",
token_uri="https://oauth2.googleapis.com/token",
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
scopes=["https://www.googleapis.com/auth/youtube.upload"]
)
youtube = build("youtube", "v3", credentials=creds)
request = youtube.videos().insert(
part="snippet,status",
body={
"snippet": {"title": "My Video", "description": "Test"},
"status": {"privacyStatus": "private"}
},
media_body="video.mp4"
)
response = request.execute()
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
creds = Credentials(
None,
refresh_token="YOUR_REFRESH_TOKEN",
token_uri="https://oauth2.googleapis.com/token",
client_id="YOUR_CLIENT_ID",
client_secret="YOUR_CLIENT_SECRET",
scopes=["https://www.googleapis.com/auth/youtube.upload"]
)
youtube = build("youtube", "v3", credentials=creds)
request = youtube.videos().insert(
part="snippet,status",
body={
"snippet": {"title": "My Video", "description": "Test"},
"status": {"privacyStatus": "private"}
},
media_body="video.mp4"
)
response = request.execute()