YouTube Data API (v3) Device Authentifikation in Python

Sa, 02.05.2015 - 10:40 -- Daniel Espendiller

 youtube_data_api_v3_device_authentificationWar es der YouTube API v2 noch möglich mittels ClientLogin Verfahren einen User Access-Token mit Name und Password zu erhalten, geht dieses in OAuth 2.0 nicht mehr. Jede Benutzeranmeldung muss zwingend in irgendeiner Form per Browser stattfinden z.B. über einen Redirect-Callback. Die Implementierung von MyTube: Youtube auf der Dreambox mit Enigma2 funktioniert somit nach der Abschaltung der alten API nicht mehr. Youtube bietet für Geräte ab API v3, also wo kein Browser bereitsteht, den sogenannte OAuth2 Devices Flow an. Es wird einfach ein Gerät mit einer simple Code Eingabe mit einem Benutzer verknüpft.

Code: Authentifikation in Python

Hier wird ein Device Code erzeugt. Als YouTube Account Daten muss man sich einen "Installed Applikation - Client-ID für native Anwendung" Code erzeugen bzw. exportieren aus der Google Developer Console. Alternative gibt hier noch ein Beispiel für curl.

import httplib2
import os
from apiclient import discovery
from oauth2client import client
import json
 
import httplib2
import urllib
import time
 
YOUTUBE_API_CLIENT_DEVICE_URL = "https://accounts.google.com/o/oauth2/device/code"
YOUTUBE_API_CLIENT_DEVICE_TOKEN = "https://accounts.google.com/o/oauth2/device/code"
 
YOUTUBE_API_CLIENT_ID = "xxxx.apps.googleusercontent.com"
YOUTUBE_API_CLIENT_SECRET = "xxxxx"
YOUTUBE_API_SCOPE = "https://www.googleapis.com/auth/youtube"
 
def getUserCode():
 
    params = urllib.urlencode({
        'client_id': YOUTUBE_API_CLIENT_ID,
        'scope': YOUTUBE_API_SCOPE,
    })
 
    response, content = httplib2.Http().request(YOUTUBE_API_CLIENT_DEVICE_URL, 'POST', params,
        headers={'Content-type': 'application/x-www-form-urlencoded'}
    )
 
    jsonResponse = json.loads(content)
    if "device_code" not in jsonResponse or "user_code" not in jsonResponse:
        return Null
 
    return jsonResponse
 
def getRefreshedToken(token):
 
    params = urllib.urlencode({
        'client_id': YOUTUBE_API_CLIENT_ID,
        'client_secret': YOUTUBE_API_CLIENT_SECRET,
        'refresh_token': token,
        'grant_type': 'refresh_token'
    })
 
    response, content = httplib2.Http().request(YOUTUBE_API_CLIENT_DEVICE_TOKEN_REFRESH, 'POST', params,
        headers={'Content-type': 'application/x-www-form-urlencoded'}
    )
 
    jsonResponse = json.loads(content)
    print jsonResponse
 
    if "access_token" not in jsonResponse:
        return None
 
    return jsonResponse
 
def getToken(code):
 
    #credentials_from_code
    url = 'https://accounts.google.com/o/oauth2/token'
 
    params = urllib.urlencode({
        'client_id': YOUTUBE_API_CLIENT_ID,
        'client_secret': YOUTUBE_API_CLIENT_SECRET,
        'code': code,
        'grant_type': 'http://oauth.net/grant_type/device/1.0',
    })
 
    response, content = httplib2.Http().request(url, 'POST', params,
        headers={'Content-type': 'application/x-www-form-urlencoded'}
    )
 
    return json.loads(content)
 
def getCredentials():
 
    # last access token
    access_token = "foo"
    refresh_token = "foo"
 
    return OAuth2Credentials(
        access_token=access_token,
        client_id=YOUTUBE_API_CLIENT_ID,
        client_secret=YOUTUBE_API_CLIENT_SECRET,
        refresh_token=refresh_token,
        token_expiry=None,
        token_uri=YOUTUBE_API_CLIENT_DEVICE_TOKEN_REFRESH,
        user_agent=None
    )
 
device = getUserCode()
print "Got device request with '%s' and '%s'" % (device["verification_url"], device["user_code"])
 
interval = device.get("interval", 5)
 
for i in range(1, 60 / int(interval)):
    time.sleep(interval)
    token = getToken(device["device_code"])
    if "error" in token:
        print "Got request error '%s'" % token["error"]
 
    if "access_token" in token and "refresh_token" in token:
        print token
        break

Status Abfragen

youtube_data_api_v3_device_python Ein "Device -> Benutzer Verknüpfung" Status muss kontinuierlich abgefragt werden bis der Benutzer den Code eingegeben hat. Solang hier nichts passiert ist wird ein pending Status zurückgegeben. Wenn der Benutzer den Vorgang im externen Browser durchgeführt hat, gibt es Tokens zum Weiterarbeiten.

root@device:/media/net# python foo.py
Got device request with 'https://www.google.com/device' and 'BXJC-QTVP'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
Got request error 'authorization_pending'
{u'access_token': u'ya29.ZwFuC-ySd3ALraod7KcZzdnSqqKzldD7BGGQJneoG8Vhge-xxxx', u'token_type': u'Bearer', u'expires_in': 3600, u'refresh_token': u'1/_zQPkMfQrhonGssOhiOdxxx'}

Meine Uploads

import httplib2
 
from apiclient.discovery import build
 
# This OAuth 2.0 access scope allows for read-only access to the authenticated
# user's account, but not other types of account access.
YOUTUBE_READONLY_SCOPE = "https://www.googleapis.com/auth/youtube.readonly"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
 
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
  http=getCredentials().authorize(httplib2.Http()))
 
# Retrieve the contentDetails part of the channel resource for the
# authenticated user's channel.
channels_response = youtube.channels().list(
  mine=True,
  part="contentDetails"
).execute()
 
print channels_response
<python>