1
votes

I'm trying to authenticate to use Google Sheets API. I'm starting to loose my mind over this, because I've been stuck at this problem for two days.

In my Google Console I have set the Credentials -> OAuth 2.0 Client IDs -> Authorized redirect URIs as https://stage.domain.com/ and https://stage.domain.com.

When I visit https://stage.domain.com, I'm redirected to the accounts.google.com to authorize my app. I select my account and click on "Allow" button. I'm redirected to the https://stage.domain.com/?code=4/...&scope=https://www.googleapis.com/auth/spreadsheets.readonly and get the {"error":"redirect_uri_mismatch","error_description":"Bad Request"} from $client->fetchAccessTokenWithAuthCode function.

What am I doing wrong? I'm running PHP and I'm using google/apiclient^2.0 from Composer.

 $configPath = __DIR__ . "/";

 // 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( 'App name matching Google Console 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 . 'secret.json' );
 $client->setAccessType( 'offline' );

 $actual_link = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

 // 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( $actual_link );

 // 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 ) );
 }
 //var_dump( $accessToken ); die();

 // 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() ) );
 }

I'm running this code from an actual server that is publicly available, this is not a local machine.

1

1 Answers

0
votes

The magic is in the redirect URL. Is has to end with trailing slash. I have no idea, why is Google so strict, but that is the solution to my problem.


Wrong redirect url: https://stage.domain.com.

Correct redirect url: https://stage.domain.com/.