Search code examples
google-photosgoogle-photos-api

Getting 403 Forbidden when using Google Photos API


I'm sorry but English is not my first language and my English is broken.

I'm trying to download my 3000+ pictures using Google Photos API with Python.

First I downloaded MediaItems list with this code.

from pathlib import Path
from requests_oauthlib import OAuth2Session
import json

api_url = "https://photoslibrary.googleapis.com/v1/mediaItems"
scope = ["https://www.googleapis.com/auth/photoslibrary.readonly"]


def save_token(token):
    token = {
        "access_token": token.get("access_token"),
        "refresh_token": token.get("refresh_token"),
        "token_type": token.get("token_type"),
        "expires_in": token.get("expires_in")
    }
    Path("token.json").write_text(json.dumps(token))


def load_token():
    token = {
        "access_token": "",
        "refresh_token": "",
        "token_type": "",
        "expires_in": "-30",
    }
    path = Path("token.json")
    if path.exists():
        token = json.loads(path.read_text())
    return token


def login():
    auth_info = json.loads(Path("credentials.json").read_text()).get("installed", None)
    assert auth_info is not None
    token = load_token()
    extras = {
        "client_id": auth_info.get("client_id"),
        "client_secret": auth_info.get("client_secret"),
    }
    google = OAuth2Session(
        auth_info.get("client_id"),
        scope=scope,
        token=token,
        auto_refresh_kwargs=extras,
        token_updater=save_token,
        auto_refresh_url=auth_info.get("token_uri"),
        redirect_uri=auth_info.get("redirect_uris")[0]
    )
    if not google.authorized:
        authorization_url, state = google.authorization_url(
            auth_info.get("auth_uri"),
            access_type="offline",
            prompt="select_account"
        )
        print("Access {} and paste code.".format(authorization_url))
        access_code = input(">>> ")
        google.fetch_token(
            auth_info.get("token_uri"),
            client_secret=auth_info.get("client_secret"),
            code=access_code
        )
        assert google.authorized
        save_token(google.token)
    return google


def test():
    google = login()
    response = google.get(api_url)
    print(response.text)


if __name__ == "__main__":
    test()

This code worked without problems and I downloaded about 30 json files (contains 3000 pictures information) with nextPageToken.

After that, I tried to download these pictures by this code.

The photo_info_list variable contains all MediaItems.

photo_download_format = "{base}=w{width}-h{height}"

def download_photos(photo_info_list):
    google = login()
    for photo_info in photo_info_list:
        photo_id = photo_info.get("id", "dummy_id")
        base_url = photo_info.get("baseUrl")
        metadata = photo_info.get("mediaMetadata")
        filename = photo_info.get("filename")
        download_url = photo_download_format.format(
            base=base_url,
            width=metadata["width"],
            height=metadata["height"]
        )
        response = google.get(download_url)
        # save_picture

This code worked well for first 162 pictures (about 270MB) but then I got 403 forbidden error.

I deleted token and tried login procedures again, created another credentials but got the same errors.

Does anyone know what is the problem?

Any suggestion or information are really appreciate. Thank you!


Solution

  • baseUrls expire in 60 minutes after acquisition. Per the documentation for Google Photos APIs

    You also shouldn't store baseUrls, which expire after approximately 60 minutes.

    The most likely explanation is that your baseUrl has expired in the middle of downloading.