0

Does anyone have an example of how to use the google photos API in 2023? I'm specifying the year because if I try to search for documentation for this, I end up on a photos.get (from google) with sample code that when I run it, gives me an error that the documented approach is already deprecated:

"You have created a new client application that uses libraries for user
authentication or authorization that will soon be deprecated. New clients must
use the new libraries instead; existing clients must also migrate before these
libraries are deprecated. See the [Migration
Guide](https://developers.google.com/identity/gsi/web/guides/gis-migration) for
more information."

I'm trying to figure out how to use this API endpoint in Javascript to access the contents of a public Google Photos album:

https://photoslibrary.googleapis.com/v1/albums/{albumId}

It seems for public album this should be fairly straight-forward. But so far it looks like oauth is needed, even to access something like a public photo album.

Is it really this hard?

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
Tim Herzog
  • 505
  • 1
  • 5
  • 11
  • please edit your question and include your code. – Linda Lawton - DaImTo Jan 17 '23 at 08:59
  • 1
    You did not mention the language which you want to use. I managed to make it work with javascript, but in general it is a big disappointment. The API allows you to view all photos, but allows you to edit only those albums and those media items created by your app. Thus all content uploaded by your google photos app is only viewable. I find it not worth to dive deep into it at all unless Google comes up with new scope giving full edit rights to all content. – Igor Mizak Mar 19 '23 at 21:18

1 Answers1

1

The issue you are having is that the sample you are using is from the old JavaScript signin/authorization library.

Google has split that up now you need to use Authorizing for Web as you can guess google has a lot of samples to be updated. I doubt they have updated everything.

I have a QuickStart created. Make sure that you create web application credentials on google developer console and create an api key.

<!DOCTYPE html>
<html>
<head>
    <title>Photos API Quickstart</title>
    <meta charset="utf-8" />
</head>
<body>
<p>Photos API Quickstart</p>

<!--Add buttons to initiate auth sequence and sign out-->
<button id="authorize_button" onclick="handleAuthClick()">Authorize</button>
<button id="signout_button" onclick="handleSignoutClick()">Sign Out</button>

<pre id="content" style="white-space: pre-wrap;"></pre>

<script type="text/javascript">
    /* exported gapiLoaded */
    /* exported gisLoaded */
    /* exported handleAuthClick */
    /* exported handleSignoutClick */

    // TODO(developer): Set to client ID and API key from the Developer Console
    const CLIENT_ID = '[REDACTED]';
    const API_KEY = '[REDACTED]';

    // Discovery doc URL for APIs used by the quickstart
    const DISCOVERY_DOC = 'https://www.googleapis.com/discovery/v1/apis/photoslibrary/v1/rest';

    // Authorization scopes required by the API; multiple scopes can be
    // included, separated by spaces.
    const SCOPES = 'https://www.googleapis.com/auth/photoslibrary.readonly';

    let tokenClient;
    let gapiInited = false;
    let gisInited = false;

    document.getElementById('authorize_button').style.visibility = 'hidden';
    document.getElementById('signout_button').style.visibility = 'hidden';

    /**
     * Callback after api.js is loaded.
     */
    function gapiLoaded() {
        gapi.load('client', initializeGapiClient);
    }

    /**
     * Callback after the API client is loaded. Loads the
     * discovery doc to initialize the API.
     */
    async function initializeGapiClient() {
        await gapi.client.init({
            apiKey: API_KEY,
            discoveryDocs: [DISCOVERY_DOC],
        });
        gapiInited = true;
        maybeEnableButtons();
    }

    /**
     * Callback after Google Identity Services are loaded.
     */
    function gisLoaded() {
        tokenClient = google.accounts.oauth2.initTokenClient({
            client_id: CLIENT_ID,
            scope: SCOPES,
            callback: '', // defined later
        });
        gisInited = true;
        maybeEnableButtons();
    }

    /**
     * Enables user interaction after all libraries are loaded.
     */
    function maybeEnableButtons() {
        if (gapiInited && gisInited) {
            document.getElementById('authorize_button').style.visibility = 'visible';
        }
    }

    /**
     *  Sign in the user upon button click.
     */
    function handleAuthClick() {
        tokenClient.callback = async (resp) => {
            if (resp.error !== undefined) {
                throw (resp);
            }
            document.getElementById('signout_button').style.visibility = 'visible';
            document.getElementById('authorize_button').innerText = 'Refresh';
            await listAlbums();
        };

        if (gapi.client.getToken() === null) {
            // Prompt the user to select a Google Account and ask for consent to share their data
            // when establishing a new session.
            tokenClient.requestAccessToken({prompt: 'consent'});
        } else {
            // Skip display of account chooser and consent dialog for an existing session.
            tokenClient.requestAccessToken({prompt: ''});
        }
    }

    /**
     *  Sign out the user upon button click.
     */
    function handleSignoutClick() {
        const token = gapi.client.getToken();
        if (token !== null) {
            google.accounts.oauth2.revoke(token.access_token);
            gapi.client.setToken('');
            document.getElementById('content').innerText = '';
            document.getElementById('authorize_button').innerText = 'Authorize';
            document.getElementById('signout_button').style.visibility = 'hidden';
        }
    }

    /**
     * Print metadata for first 10 Albums.
     */
    async function listAlbums() {
        let response;
        try {
            response = await gapi.client.photoslibrary.albums.list({
                'pageSize': 10,
                'fields': 'albums(id,title)',
            });
        } catch (err) {
            document.getElementById('content').innerText = err.message;
            return;
        }
        const albums = response.result.albums;
        if (!albums || albums.length == 0) {
            document.getElementById('content').innerText = 'No albums found.';
            return;
        }
        // Flatten to string to display
        const output = albums.reduce(
            (str, album) => `${str}${album.title} (${album.id}\n`,
            'albums:\n');
        document.getElementById('content').innerText = output;
    }
</script>
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script>
<script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
</body>
</html>

public album.

The thing is you say your after public albums, if the album is in fact public then you should be able to get away with just using the api key. You should only need to be authorized if its private user data.

Update: after a bit of digging im not even sure this library will allow you to only login with an api key with out sending a valid client id. I have sent an email off to the Identity team to see if they have something they can share.

Update:

I got a message back from the team:

A client ID is required even to access content the user has made available to everyone.

So even if the data is public you will have to register a client id and request permissions of the user.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Many thanks, and I see you posted a similar response here: https://stackoverflow.com/questions/74587665/how-can-i-in-javascript-get-my-a-json-list-of-my-google-photos-album. And thank you for confirming that an API key alone won't work. Unfortunately for me that means that Google's platform won't work in the way I had hoped. My goal is to build a photo browser using google photos to organize photos and metadata. I can't expect users to login to google if all they want to do is view photos that are already public. – Tim Herzog Jan 18 '23 at 12:48
  • if you want to drop the library the code to send a request with the API key is easy. your just going to have to parse the response – Linda Lawton - DaImTo Jan 18 '23 at 13:59