Google Client API - Missing require parameter: redirect_uri

36,098

Solution 1

I got it to work. What I had to do was go back into Google Developer Console and delete the project I had created. Then when making a NEW project it allowed me to save my localhost url. The issue that was occuring was when I went to go add my localhost url to the redirect url it would say its not possible at this time. When I set the redirect url before hitting the create button it accepts it just fine.

Solution 2

Just use method setRedirectUri($absoluteUrl) on a client object:

$client = new Google_Client();
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

via:

https://developers.google.com/api-client-library/php/auth/web-app

Solution 3

Google's "PHP Quick Start" documentation for the Sheet API seems to be out of date at https://developers.google.com/sheets/api/quickstart/php.

To get their demo working with PHP 7.2+ I had to modify quite a bit, and it's not all that clear what's going on. Below is a commented, updated version of their quick start that may be helpful to anyone else having trouble working with the Google Sheets API and PHP.

<?php
/**
 * Updated Google Sheets Quickstart
 *
 * https://developers.google.com/sheets/api/quickstart/php
 */
require __DIR__ . '/vendor/autoload.php';

/**
* Appends one slash at the end, and removes any extra slashes
* https://stackoverflow.com/a/9339669/812973
*
* @return string $path with the slash appended
*/
function addTrailingSlash ($path)
{
    return rtrim ($path, '/') . '/';
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient() {

     // Change this to a secure location where you'll save your config *.json files
     // Make sure it isn't publicly available on the web
    $configPath = addTrailingSlash (getcwd());

    // This get's generated by the script, so don't create it
    $credentialsPath = $configPath . 'credentials.json';

    $client = new Google_Client();

    // Matches the "Application Name" you enter during the "Step 1" wizard
    $client->setApplicationName( 'API App Name' );
    $client->setScopes( Google_Service_Sheets::SPREADSHEETS_READONLY );

    // You need to go through "Step 1" steps to generate this file: https://developers.google.com/sheets/api/quickstart/php
    $client->setAuthConfig( $configPath . 'client_secret.json' );
    $client->setAccessType( 'offline' );

    // This must match the "callback URL" that you enter under "OAuth 2.0 client ID" in the Google APIs console at https://console.developers.google.com/apis/credentials
    $client->setRedirectUri( 'https://' . $_SERVER['HTTP_HOST'] . '/' . basename( __FILE__, '.php' ) );

    // We have a stored credentials file, try using the data from there first
    if ( file_exists( $credentialsPath ) ) {
        $accessToken = json_decode( file_get_contents( $credentialsPath ), true );
    }

    // No stored credentials found, we'll need to request them with OAuth
    else {

        // Request authorization from the user
        $authUrl = $client->createAuthUrl();
        if ( ! isset( $_GET['code'] ) ) {
            header( "Location: $authUrl", true, 302 );
            exit;
        }

        // The authorization code is sent to the callback URL as a GET parameter.
        // We use this "authorization code" to generate an "access token". The
        // "access token" is what's effectively used as a private API key.
        $authCode = $_GET['code'];
        $accessToken = $client->fetchAccessTokenWithAuthCode( $authCode );

        // Create credentials.json if it doesn't already exist (first run)
        if ( ! file_exists( dirname( $credentialsPath ) ) ) {
            mkdir( dirname( $credentialsPath ), 0700, true );
        }

        // Save the $accessToken object to the credentials.json file for re-use
        file_put_contents( $credentialsPath, json_encode( $accessToken ) );
    }

    // Provide client with API access token
    $client->setAccessToken( $accessToken );

    // If the $accessToken is expired then we'll need to refresh it
    if ( $client->isAccessTokenExpired() ) {
        $client->fetchAccessTokenWithRefreshToken( $client->getRefreshToken() );
        file_put_contents( $credentialsPath, json_encode( $client->getAccessToken() ) );
    }

    return $client;
}

// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets( $client );

// Get values from a spreadheet and print
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();

if (empty($values)) {
    print "No data found.\n";
} else {
    print "Name, Major:\n";
    foreach ($values as $row) {
        // Print columns A and E, which correspond to indices 0 and 4.
        printf("%s, %s\n", $row[0], $row[4]);
    }
}

Solution 4

This answer might not fully satisfy your needs, but:

If you only need read access to the sheet, all you need is a Google Service Account credentials file (credentials.json).

One can simply slice out the token-retrieving part of the example like so:

<?php
require __DIR__ . '/vendor/autoload.php';

if (php_sapi_name() != 'cli') {
    throw new Exception('This application must be run on the command line.');
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient()
{
    $client = new Google_Client();
    $client->setApplicationName('Google Sheets API PHP Quickstart');
    $client->setScopes(Google_Service_Sheets::SPREADSHEETS_READONLY);
    $client->setAuthConfig('credentials.json');
    $client->setAccessType('offline');
    $client->setPrompt('select_account consent');
    return $client;
}


// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets($client);

// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
$spreadsheetId = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms';
$range = 'Class Data!A2:E';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();

if (empty($values)) {
    print "No data found.\n";
} else {
    print "Name, Major:\n";
    foreach ($values as $row) {
        // Print columns A and E, which correspond to indices 0 and 4.
        printf("%s, %s\n", $row[0], $row[4]);
    }
}

Google should have mentioned this in their example IMO.

Solution 5

My problem was i'm not initialized the URI in Google Console to fix the problem :

1- go to your project https://console.cloud.google.com/ (Select project from top)

2- Search for "Google sheet API" make sure it's enabled

3- On left menu Click on "Credentials"

4- If you're already created "OAuth 2.0 Client IDs" just click on edit and add URI else create new "OAuth 2.0 Client IDs"

5- Remember to re-download "OAuth 2.0 Client IDs" it will be something like "client_secret_XXX.apps.googleusercontent.com" rename it to credentials.json and set it on your project

Share:
36,098
Joshua Blevins
Author by

Joshua Blevins

I am a PHP developer that just starting learning Objective-C and Cocoa for a business venture i am planning.

Updated on July 09, 2022

Comments

  • Joshua Blevins
    Joshua Blevins almost 2 years

    So I followed the quickstart guide and decided to break it into a class called scheduler. I am working on the the authentication code, but I keep getting this: "Error 400 (OAuth 2 Error) Error Invalid Request Missing required Parameter: redirect_uri".

    class scheduler{
    
    //The Google Client object
    private $googleClient;
    
    //the Google Calendar Service ojbect
    private $calendarService;
    
    /*
    *   Google Calendar Setup
    *
    *   This creates a Google Client object so that you may create a Google Calendar object.
    *
    */
    function __construct(){
        //set the application name
        define("APPLICATION_NAME", "Web client 1");
        //
        define("CREDENTIALS_PATH", "~/scheduler/credentials.json");
        //
        define("CLIENT_SECRET_PATH", __DIR__ . "/scheduler/client_secret.json");
        //
        define("SCOPES", implode(" ", array(Google_Service_Calendar::CALENDAR_READONLY)));
    
        /*if(php_sapi_name() != "cli"){
            throw new Exception("This application must be run on the command line");    
        }*/
    
        //create the google client
        $this->googleClient = new Google_Client();
    
        //setup the client
        $this->googleClient->setApplicationName(APPLICATION_NAME);
        $this->googleClient->setDeveloperKey("AIzaSyBmJLvNdMYuFhVpWalkUdyStrEBoVEayYM");
        $this->googleClient->setScopes(SCOPES);
        $this->googleClient->setAuthConfigFile(CLIENT_SECRET_PATH);
        $this->googleClient->setAccessType("offline");
    
        //get the credentials file path
        $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
    
        //if the file exists
        if(file_exists($credentialsPath)){
    
            //get the credentials from the file
            $accessToken = file_get_contents($credentialsPath); 
    
        }//if it does not
        else{
    
            //request the authorization url
            $authURL = $this->googleClient->createAuthUrl();
            //print the authorization ulr
            echo "<a href=\"$authURL\">Press Me</a><br /><br />";
    
            //prompt the user to enter the auth code
            print("Enter authentication code: ");
    
            //
            $authCode = trim(fgets(STDIN));
    
            //exchange authorization for an access token
            $accessToken = $this->googleClient->authenticate($authCode);
    
            //store credentials to disk
            if(!file_exists(dirname($credentialsPath))){
                mkdir(dirname($credentialsPath), 0700, true);   
            }
    
            //put the contents into the credential files
            file_put_contents($credentialsPath, $accessToken);
        }
    
        $this->googleClient->setAccessToken($accessToken);
    
        //refresh token if its expired
        if($this->googleClient->isAccessTokenExpired()){
            $this->googleClient->refreshToken($client->getRefreshToken());
    
            file_put_contents($credentialsPath, $this->googleClient->getAccessToken()); 
        }
    }
    

    I found the cause of the problem with no solution in sight. Under my Google Developer Console I tried putting "http://localhost/" into the Authorized redirect URIs section. It gives me this error "Sorry, there’s a problem. If you entered information, check it and try again. Otherwise, the problem might clear up on its own, so check back later." Is there a way to make Google Developer Console to accept the redirect uri of a localhost server?

  • Sᴀᴍ Onᴇᴌᴀ
    Sᴀᴍ Onᴇᴌᴀ about 8 years
    Thanks for posting your solution - I was able to edit an existing project and add an Authorized redirect URI...
  • Joshua Blevins
    Joshua Blevins about 8 years
    No problem fellow developer. Glad to help.
  • Greg Thompson
    Greg Thompson almost 8 years
    The reason this is, is because your client secret json file that you download needs to be updated as well. So if you create your credentials without a uri and download the json, the json doesn't have the 'redirect_uris' property. If you then go and add it in the dashboard, you need to re-download the client secret json and add it to your project.
  • iamface
    iamface over 7 years
    Will this work with a service account? There is no option to add a redirect_uri.
  • Joshua Blevins
    Joshua Blevins over 7 years
    What is a service account? Can you give more details so that I may attempt to recreate your specific issue?
  • gyaani_guy
    gyaani_guy almost 7 years
    @GregThompson is exactly correct. Thanks a lot. Comment could have been posted as an answer
  • ratiotile
    ratiotile almost 6 years
    After adding the redirect, follow the quickstart guide up to Step 4a where you browse to the login url, sign in, and are redirected. The script will redirect you to the provided redirect url, with the verification code appended as a url parameter. You need to copy and paste it back into the terminal to complete the tutorial.
  • Rigal
    Rigal over 4 years
    Hello, @Kevin Leary, I want to run this code from the browser, not the command line. I want to display all sheet data on the PHP web page. I follow this "youtube.com/watch?v=iTZyuszEkxI" tutorial but it's not working on brower when hit page URL . Would you please help me to fix this issue?