Click here to Skip to main content
15,389,911 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Server: Ubuntu Server 20.04 LTS on AWS EC2
PHP 7.4.3
Chrome version 101.0.4951.67
Using the client library for PHP (Installed with Composer version 2.3.5)

Should I do something with the API key in addition to OAuth authentication?
When I run the YouTube Data API listSubscriptions() method, I got the following error:

When excute Subscriptions list method of YouTube Data API,
this error happened. I'm not sure why the access was forbidden:


Fatal error: Uncaught Google\Service\Exception: { "error": { "code": 403, "message": "The request is missing a valid API key.", "errors": [ { "message": "The request is missing a valid API key.", "domain": "global", "reason": "forbidden" } ], "status": "PERMISSION_DENIED" } } in /home/ubuntu/vendor/google/apiclient/src/Http/REST.php:128 Stack trace: #0 /home/ubuntu/vendor/google/apiclient/src/Http/REST.php(103): Google\Http\REST::decodeHttpResponse() #1 [internal function]: Google\Http\REST::doExecute() #2 /home/ubuntu/vendor/google/apiclient/src/Task/Runner.php(182): call_user_func_array() #3 /home/ubuntu/vendor/google/apiclient/src/Http/REST.php(66): Google\Task\Runner->run() #4 /home/ubuntu/vendor/google/apiclient/src/Client.php(922): Google\Http\REST::execute() #5 /home/ubuntu/vendor/google/apiclient/src/Service/Resource.php(238): Google\Client->execute() #6 /home/ubuntu/vendor/google/apiclient-services/src/YouTube/Resource/Subscriptions.php(125): Google\Ser in /home/ubuntu/vendor/google/apiclient/src/Http/REST.php on line 128


Here is the PHP with the error:

userAuthorization.php
<?php

set_include_path('/home/ubuntu');

require_once 'vendor/autoload.php';

$CLIENT_ID = "xxxxxxxx";

$OAUTH2_CLIENT_SECRET = 'YYYYYY';

// Get $id_token via HTTPS POST.
$id_token = $_POST['credential'];


$client = new Google_Client();  // Specify the CLIENT_ID of the app that accesses the backend

$client->setClientId($CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);

// Verify $id_token
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  echo "Token is Valid";


  $client->setScopes('https://www.googleapis.com/auth/youtube.force-ssl');


  $youtube = new Google_Service_YouTube($client);

  $params['mine'] = 'true';

  $subsclistsResponse = $youtube->subscriptions->listSubscriptions('snippet', $params);


  // If request specified a G Suite domain:
  //$domain = $payload['hd'];

} else {
  // Invalid ID token
  echo "Token is Invalid";
}


I used client library for PHP. (Installed its package with Composer version 2.3.5)

I read API Guide's Subscriptions list method section,
and learned the error means "The requester is not allowed to access the requested subscriptions."(403 forbidden error)

(Of course I mean my subscription.)


What I have tried:

Until I get an error,

・I'd got an OAuth client ID from Google API Console.
Also enabled Google+ API & YouTube Data API v3.
And I added my redirect & origin URIs.


・Call requestAccessToken () and allow access in the user consent dialog

・Click the Sign in with Google button

・Then, the error occurs. Error message is "The request is missing a valid API key."


Below are the HTML of the "Login with Google" page and
a "Please permit our Access" button & a getToken () script that triggers a user consent prompt.
That's all, thanks.

<!DOCTYPE html>
<html>
  <head>
    
    <script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
  </head>
  <body>
          <script>
          var client;
          var access_token;

          function initClient() {

           <!-- Initialize a new token client with client ID of App. -->
           client = google.accounts.oauth2.initTokenClient({
           client_id: 'xxxxxxxx',

           <!-- Configure OAuth2.0 scope which the user accesses.   -->
           scope: 'https://www.googleapis.com/auth/youtube.readonly \
                  https://www.googleapis.com/auth/youtube.force-ssl',

           <!-- Google returns TokenResponse where access-token & list of access permitted by user was stored.  -->
           callback: (tokenResponse) => {
                   if (tokenResponse && tokenResponse.access_token) {

                           <!-- After requestAccessToken() called callback function and access-token, use hasGrantedAllScopes() to comfirm that user accepted  requested scopes -->
                           if (google.accounts.oauth2.hasGrantedAllScopes(tokenResponse,
                             'https://www.googleapis.com/auth/youtube.readonly',
                                   'https://www.googleapis.com/auth/youtube.force-ssl')){
                           }

                           <!-- return access-token -->
                           access_token = tokenResponse.access_token;
                   }
           },

          });

         }

         <!-- get access-token  -->
         function getToken() {
          client.requestAccessToken();
         }

          </script>

          <!-- Configure & display Sign in with Google button (If clicked, jump to URL spicified with "data-login_uri" ) -->
          <div id="g_id_onload"
     data-client_id="xxxxxxxx"
     data-context="signin"
     data-ux_mode="redirect"
     data-login_uri="https://xxxxxx/gcp/userAuthorization.php"
     data-auto_prompt="false">
          </div>

          <div class="g_id_signin"
     data-type="standard"
     data-shape="rectangular"
     data-theme="outline"
     data-text="$ {button.text}"
     data-size="large"
     data-logo_alignment="left">
          </div>

    <!-- With user's click trigger getting token  -->
    <button onclick="getToken();">Please permit our Access</button><br><br>

  </body>
</html>




First, I guessed something was wrong with "scope" when the error happened.
So I implemented "User's Consent dialog",
and called requestAccessToken() of client library.
"User's Consent dialog" is successfully triggered when HTML button is clicked. In the dialog displayed some scopes like figure2 in this article: How user authorization works  |  Google Identity Services JavaScript SDK  |  Google Developers[^]

(I did this following
Migrate to Google Identity Services  |  Google Identity Services JavaScript SDK  |  Google Developers[^] )

In addition, before recieving 403 forbidden error, I'd already coded some scripts:

I implemented rendering "Sign in with Google" by following google's document (Migrating from Google Sign-In  |  Sign In With Google  |  Google Developers[^][^])

note
・At "HTML and JavaScript" section in "Migrating from Google Sign-In" document, I coded as a redirectmode; And it's successfully redirected to PHP login-endpoint page.

・At PHP, it seemed I successfully get a valid ID token,
because verifyIdToken() returned payload.
(I followed this article:Verify the Google ID token on your server side  |  Sign In With Google  |  Google Developers[^])



userAuthorization.php

PHP
<?php

set_include_path('/home/ubuntu');

require_once 'vendor/autoload.php';

$CLIENT_ID = "xxxxxxxx";

$OAUTH2_CLIENT_SECRET = 'YYYYYY';

// Get $id_token via HTTPS POST.
$id_token = $_POST['credential'];


$client = new Google_Client();  // Specify the CLIENT_ID of the app that accesses the backend

$client->setClientId($CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);

// Verify $id_token
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  echo "Token is Valid";


  $client->setScopes('https://www.googleapis.com/auth/youtube.force-ssl');


  $youtube = new Google_Service_YouTube($client);

  $params['mine'] = 'true';

  $subsclistsResponse = $youtube->subscriptions->listSubscriptions('snippet', $params);


  // If request specified a G Suite domain:
  //$domain = $payload['hd'];

} else {
  // Invalid ID token
  echo "Token is Invalid";
}
Posted
Updated 30-May-22 21:05pm
v2

Look at the error message:
The request is missing a valid API key.

You need to use your Google API key for access.
   
This article has been closed.

The error may have been caused by the OAuth "profile" scope not being set.
Also, if I added a scope, I had to destroy the token and refresh it.


The error message was "The request is missing a valid API key.",
but if you're authenticated with your OAuth client ID, you probably don't need an API key.

Authentication overview  |  Google Cloud[^]

Thanks.
   
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900