Authorize merchant account access

Here's a sample you can use for authorization:

Java

  // Copyright 2024 Google LLC 
 // 
 // Licensed under the Apache License, Version 2.0 (the "License"); 
 // you may not use this file except in compliance with the License. 
 // You may obtain a copy of the License at 
 // 
 //     https://www.apache.org/licenses/LICENSE-2.0 
 // 
 // Unless required by applicable law or agreed to in writing, software 
 // distributed under the License is distributed on an "AS IS" BASIS, 
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 // See the License for the specific language governing permissions and 
 // limitations under the License. 
 package 
  
 shopping.merchant.samples.utils 
 ; 
 import 
  
 com.google.api.client.http.GenericUrl 
 ; 
 import 
  
 com.google.api.client.http.HttpStatusCodes 
 ; 
 import 
  
 com.google.api.client.util.Key 
 ; 
 import 
  
 com.google.auth.oauth2.ClientId 
 ; 
 import 
  
 com.google.auth.oauth2.GoogleCredentials 
 ; 
 import 
  
 com.google.auth.oauth2.UserAuthorizer 
 ; 
 import 
  
 com.google.auth.oauth2.UserCredentials 
 ; 
 import 
  
 com.google.common.base.MoreObjects 
 ; 
 import 
  
 com.google.common.base.Strings 
 ; 
 import 
  
 com.google.common.collect.ImmutableList 
 ; 
 import 
  
 java.io.BufferedReader 
 ; 
 import 
  
 java.io.File 
 ; 
 import 
  
 java.io.FileInputStream 
 ; 
 import 
  
 java.io.IOException 
 ; 
 import 
  
 java.io.InputStream 
 ; 
 import 
  
 java.io.InputStreamReader 
 ; 
 import 
  
 java.io.OutputStreamWriter 
 ; 
 import 
  
 java.io.Writer 
 ; 
 import 
  
 java.math.BigInteger 
 ; 
 import 
  
 java.net.ServerSocket 
 ; 
 import 
  
 java.net.Socket 
 ; 
 import 
  
 java.net.URI 
 ; 
 import 
  
 java.nio.charset.StandardCharsets 
 ; 
 import 
  
 java.security.SecureRandom 
 ; 
 import 
  
 java.util.regex.Matcher 
 ; 
 import 
  
 java.util.regex.Pattern 
 ; 
 /** 
 * Class that contains all the authentication logic, both for service accounts and to create an 
 * OAuth 2 refresh token for the Merchant API. 
 * 
 * <p>IMPORTANT FOR OAUTH: For web app clients types, you must add {@code http://127.0.0.1} to the 
 * "Authorized redirect URIs" list in your Google Cloud Console project before running this example. 
 * Desktop app client types do not require the local redirect to be explicitly configured in the 
 * console. 
 * 
 * <p>This example will start a basic server that listens for requests at {@code 
 * http://127.0.0.1:PORT}, where {@code PORT} is dynamically assigned. 
 */ 
 public 
  
 class 
 Authenticator 
  
 { 
  
 // OAUTH2_CALLBACK_BASE_URI set to localhost by default 
  
 private 
  
 static 
  
 final 
  
 String 
  
 OAUTH2_CALLBACK_BASE_URI 
  
 = 
  
 "http://127.0.0.1" 
 ; 
  
 // Scopes for the generated OAuth2 credentials. The list here only contains the Merchant API 
  
 // scope, but you can add multiple scopes if you want to use the credentials for other Google 
  
 // APIs. 
  
 private 
  
 static 
  
 final 
  
 ImmutableList<String> 
  
 SCOPES 
  
 = 
  
 ImmutableList 
 . 
< String>builder 
 (). 
 add 
 ( 
 "https://www.googleapis.com/auth/content" 
 ). 
 build 
 (); 
  
 public 
  
 GoogleCredentials 
  
 authenticate 
 () 
  
 throws 
  
 IOException 
  
 { 
  
 Config 
  
 config 
  
 = 
  
 Config 
 . 
 load 
 (); 
  
 if 
  
 ( 
 config 
 . 
 getPath 
 () 
  
 == 
  
 null 
 ) 
  
 { 
  
 throw 
  
 new 
  
 IllegalArgumentException 
 ( 
  
 "Must update Config.java to set a configuration directory." 
 ); 
  
 } 
  
 File 
  
 serviceAccountFile 
  
 = 
  
 new 
  
 File 
 ( 
 config 
 . 
 getPath 
 (), 
  
 "service-account.json" 
 ); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Checking for service account file at: %s%n" 
 , 
  
 serviceAccountFile 
 ); 
  
 if 
  
 ( 
 serviceAccountFile 
 . 
 exists 
 ()) 
  
 { 
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "Attempting to load service account credentials" 
 ); 
  
 try 
  
 ( 
 InputStream 
  
 inputStream 
  
 = 
  
 new 
  
 FileInputStream 
 ( 
 serviceAccountFile 
 )) 
  
 { 
  
 GoogleCredentials 
  
 credential 
  
 = 
  
 GoogleCredentials 
 . 
 fromStream 
 ( 
 inputStream 
 ); 
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "Successfully loaded service account credentials" 
 ); 
  
 return 
  
 credential 
 ; 
  
 } 
  
 } 
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "No service account file found." 
 ); 
  
 // Non-service account OAuth flow below 
  
 // First see if a refresh token exists, and if so, use it 
  
 File 
  
 tokenFile 
  
 = 
  
 new 
  
 File 
 ( 
 config 
 . 
 getPath 
 (), 
  
 "token.json" 
 ); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Checking for user credentials file at: %s%n" 
 , 
  
 tokenFile 
 ); 
  
 if 
  
 ( 
 tokenFile 
 . 
 exists 
 ()) 
  
 { 
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "Loading OAuth2 refresh token." 
 ); 
  
 UserCredentials 
  
 userCredentials 
  
 = 
  
 UserCredentials 
 . 
 fromStream 
 ( 
 new 
  
 FileInputStream 
 ( 
 tokenFile 
 )); 
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "Successfully loaded OAuth2 refresh token" 
 ); 
  
 return 
  
 userCredentials 
 ; 
  
 } 
  
 // If the refresh token does not exist, attempt to use client 
  
 // credentials to get a refresh token 
  
 File 
  
 clientSecretsFile 
  
 = 
  
 new 
  
 File 
 ( 
 config 
 . 
 getPath 
 (), 
  
 "client-secrets.json" 
 ); 
  
 if 
  
 ( 
 ! 
 clientSecretsFile 
 . 
 exists 
 ()) 
  
 { 
  
 throw 
  
 new 
  
 IOException 
 ( 
  
 "No authentication credentials found. Checked the paths " 
  
 + 
  
 serviceAccountFile 
 . 
 getCanonicalPath 
 () 
  
 + 
  
 " and " 
  
 + 
  
 clientSecretsFile 
 . 
 getCanonicalPath 
 () 
  
 + 
  
 ". Please read the accompanying README." 
 ); 
  
 } 
  
  
 System 
 . 
 out 
 . 
 println 
 ( 
 "Loading OAuth2 client credentials." 
 ); 
  
 try 
  
 ( 
 InputStream 
  
 inputStream 
  
 = 
  
 new 
  
 FileInputStream 
 ( 
 clientSecretsFile 
 )) 
  
 { 
  
 ClientId 
  
 parsedClient 
  
 = 
  
 ClientId 
 . 
 fromStream 
 ( 
 inputStream 
 ); 
  
 String 
  
 clientId 
  
 = 
  
 parsedClient 
 . 
 getClientId 
 (); 
  
 String 
  
 clientSecret 
  
 = 
  
 parsedClient 
 . 
 getClientSecret 
 (); 
  
 // Creates an anti-forgery state token as described here: 
  
 // https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken 
  
 String 
  
 state 
  
 = 
  
 new 
  
 BigInteger 
 ( 
 130 
 , 
  
 new 
  
 SecureRandom 
 ()). 
 toString 
 ( 
 32 
 ); 
  
 // Creates an HTTP server that will listen for the OAuth2 callback request. 
  
 URI 
  
 baseUri 
 ; 
  
 UserAuthorizer 
  
 userAuthorizer 
 ; 
  
 AuthorizationResponse 
  
 authorizationResponse 
  
 = 
  
 null 
 ; 
  
 try 
  
 ( 
 SimpleCallbackServer 
  
 simpleCallbackServer 
  
 = 
  
 new 
  
 SimpleCallbackServer 
 ()) 
  
 { 
  
 userAuthorizer 
  
 = 
  
 UserAuthorizer 
 . 
 newBuilder 
 () 
  
 . 
 setClientId 
 ( 
 ClientId 
 . 
 of 
 ( 
 clientId 
 , 
  
 clientSecret 
 )) 
  
 . 
 setScopes 
 ( 
 SCOPES 
 ) 
  
 // Provides an empty callback URI so that no additional suffix is added to the 
  
 // redirect. By default, UserAuthorizer will use "/oauth2callback" if this is 
  
 // either 
  
 // not set or set to null. 
  
 . 
 setCallbackUri 
 ( 
 URI 
 . 
 create 
 ( 
 "" 
 )) 
  
 . 
 build 
 (); 
  
 baseUri 
  
 = 
  
 URI 
 . 
 create 
 ( 
 OAUTH2_CALLBACK_BASE_URI 
  
 + 
  
 ":" 
  
 + 
  
 simpleCallbackServer 
 . 
 getLocalPort 
 ()); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
  
 "Paste this url in your browser:%n%s%n" 
 , 
  
 userAuthorizer 
 . 
 getAuthorizationUrl 
 ( 
 "" 
 , 
  
 state 
 , 
  
 baseUri 
 )); 
  
 // Waits for the authorization code. 
  
 simpleCallbackServer 
 . 
 accept 
 (); 
  
 authorizationResponse 
  
 = 
  
 simpleCallbackServer 
 . 
 authorizationResponse 
 ; 
  
 } 
  
 if 
  
 ( 
 authorizationResponse 
  
 == 
  
 null 
  
 || 
  
 authorizationResponse 
 . 
 code 
  
 == 
  
 null 
 ) 
  
 { 
  
 throw 
  
 new 
  
 NullPointerException 
 ( 
  
 "OAuth2 callback did not contain an authorization code: " 
  
 + 
  
 authorizationResponse 
 ); 
  
 } 
  
 // Confirms that the state in the response matches the state token used to generate the 
  
 // authorization URL. 
  
 if 
  
 ( 
 ! 
 state 
 . 
 equals 
 ( 
 authorizationResponse 
 . 
 state 
 )) 
  
 { 
  
 throw 
  
 new 
  
 IllegalStateException 
 ( 
 "State does not match expected state" 
 ); 
  
 } 
  
 // Exchanges the authorization code for credentials and print the refresh token. 
  
 UserCredentials 
  
 userCredentials 
  
 = 
  
 userAuthorizer 
 . 
 getCredentialsFromCode 
 ( 
 authorizationResponse 
 . 
 code 
 , 
  
 baseUri 
 ); 
  
 System 
 . 
 out 
 . 
 printf 
 ( 
 "Your new refresh token is: %s%n" 
 , 
  
 userCredentials 
 . 
 getRefreshToken 
 ()); 
  
 // Save the refresh token to be used for the future 
  
 userCredentials 
 . 
 save 
 ( 
 new 
  
 File 
 ( 
 config 
 . 
 getPath 
 (), 
  
 "token.json" 
 ). 
 getPath 
 ()); 
  
 return 
  
 userCredentials 
 ; 
  
 } 
  
 catch 
  
 ( 
 IOException 
  
 e 
 ) 
  
 { 
  
 throw 
  
 new 
  
 IOException 
 ( 
  
 "Could not retrieve OAuth2 client credentials from the file " 
  
 + 
  
 clientSecretsFile 
 . 
 getCanonicalPath 
 ()); 
  
 } 
  
 } 
  
 /** Basic server that listens for the OAuth2 callback. */ 
  
 private 
  
 static 
  
 class 
 SimpleCallbackServer 
  
 extends 
  
 ServerSocket 
  
 { 
  
 private 
  
 AuthorizationResponse 
  
 authorizationResponse 
 ; 
  
 SimpleCallbackServer 
 () 
  
 throws 
  
 IOException 
  
 { 
  
 // Passes a port # of zero so that a port will be automatically allocated. 
  
 super 
 ( 
 0 
 ); 
  
 } 
  
 /** 
 * Blocks until a connection is made to this server. After this method completes, the 
 * authorizationResponse of this server will be set, provided the request line is in the 
 * expected format. 
 */ 
  
 @Override 
  
 public 
  
 Socket 
  
 accept 
 () 
  
 throws 
  
 IOException 
  
 { 
  
 Socket 
  
 socket 
  
 = 
  
 super 
 . 
 accept 
 (); 
  
 try 
  
 ( 
 BufferedReader 
  
 in 
  
 = 
  
 new 
  
 BufferedReader 
 ( 
  
 new 
  
 InputStreamReader 
 ( 
 socket 
 . 
 getInputStream 
 (), 
  
 StandardCharsets 
 . 
 UTF_8 
 ))) 
  
 { 
  
 String 
  
 callbackRequest 
  
 = 
  
 in 
 . 
 readLine 
 (); 
  
 // Uses a regular expression to extract the request line from the first line of the 
  
 // callback request, e.g.: 
  
 //   GET /?code=AUTH_CODE&state=XYZ&scope=https://www.googleapis.com/auth/adwords HTTP/1.1 
  
 Pattern 
  
 pattern 
  
 = 
  
 Pattern 
 . 
 compile 
 ( 
 "GET +([^ ]+)" 
 ); 
  
 Matcher 
  
 matcher 
  
 = 
  
 pattern 
 . 
 matcher 
 ( 
 Strings 
 . 
 nullToEmpty 
 ( 
 callbackRequest 
 )); 
  
 if 
  
 ( 
 matcher 
 . 
 find 
 ()) 
  
 { 
  
 String 
  
 relativeUrl 
  
 = 
  
 matcher 
 . 
 group 
 ( 
 1 
 ); 
  
 authorizationResponse 
  
 = 
  
 new 
  
 AuthorizationResponse 
 ( 
 OAUTH2_CALLBACK_BASE_URI 
  
 + 
  
 relativeUrl 
 ); 
  
 } 
  
 try 
  
 ( 
 Writer 
  
 outputWriter 
  
 = 
  
 new 
  
 OutputStreamWriter 
 ( 
 socket 
 . 
 getOutputStream 
 ())) 
  
 { 
  
 outputWriter 
 . 
 append 
 ( 
 "HTTP/1.1 " 
 ); 
  
 outputWriter 
 . 
 append 
 ( 
 Integer 
 . 
 toString 
 ( 
 HttpStatusCodes 
 . 
 STATUS_CODE_OK 
 )); 
  
 outputWriter 
 . 
 append 
 ( 
 " OK\n" 
 ); 
  
 outputWriter 
 . 
 append 
 ( 
 "Content-Type: text/html\n\n" 
 ); 
  
 outputWriter 
 . 
 append 
 ( 
 "<b>" 
 ); 
  
 if 
  
 ( 
 authorizationResponse 
 . 
 code 
  
 != 
  
 null 
 ) 
  
 { 
  
 outputWriter 
 . 
 append 
 ( 
 "Authorization code was successfully retrieved." 
 ); 
  
 } 
  
 else 
  
 { 
  
 outputWriter 
 . 
 append 
 ( 
 "Failed to retrieve authorization code." 
 ); 
  
 } 
  
 outputWriter 
 . 
 append 
 ( 
 "</b>" 
 ); 
  
 outputWriter 
 . 
 append 
 ( 
 "<p>Please check the console output from <code>" 
 ); 
  
 outputWriter 
 . 
 append 
 ( 
 Authenticator 
 . 
 class 
 . 
 getSimpleName 
 ()); 
  
 outputWriter 
 . 
 append 
 ( 
 "</code> for further instructions." 
 ); 
  
 } 
  
 } 
  
 return 
  
 socket 
 ; 
  
 } 
  
 } 
  
 /** Response object with attributes corresponding to OAuth2 callback parameters. */ 
  
 static 
  
 class 
 AuthorizationResponse 
  
 extends 
  
 GenericUrl 
  
 { 
  
 /** The authorization code to exchange for an access token and (optionally) a refresh token. */ 
  
 @Key 
  
 String 
  
 code 
 ; 
  
 /** Error from the request or from the processing of the request. */ 
  
 @Key 
  
 String 
  
 error 
 ; 
  
 /** State parameter from the callback request. */ 
  
 @Key 
  
 String 
  
 state 
 ; 
  
 /** 
 * Constructs a new instance based on an absolute URL. All fields annotated with the {@link Key} 
 * annotation will be set if they are present in the URL. 
 * 
 * @param encodedUrl absolute URL with query parameters. 
 */ 
  
 public 
  
 AuthorizationResponse 
 ( 
 String 
  
 encodedUrl 
 ) 
  
 { 
  
 super 
 ( 
 encodedUrl 
 ); 
  
 } 
  
 // @Override 
  
 public 
  
 String 
  
 toString 
 () 
  
 { 
  
 return 
  
 MoreObjects 
 . 
 toStringHelper 
 ( 
 getClass 
 ()) 
  
 . 
 add 
 ( 
 "code" 
 , 
  
 code 
 ) 
  
 . 
 add 
 ( 
 "error" 
 , 
  
 error 
 ) 
  
 . 
 add 
 ( 
 "state" 
 , 
  
 state 
 ) 
  
 . 
 toString 
 (); 
  
 } 
  
 } 
 } 
  
 

PHP

 < ?php 
 /** 
 * Copyright 2025 Google LLC 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *     https://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
 require_once __DIR__ . '/../../vendor/autoload.php'; 
 require_once __DIR__ . '/Config.php'; 
 use Google\Auth\CredentialsLoader; 
 use Google\Auth\OAuth2; 
 use Google\Auth\Credentials\UserRefreshCredentials; 
 use Psr\Http\Message\ServerRequestInterface; 
 use React\EventLoop\Loop; 
 use React\Http\HttpServer; 
 use React\Http\Message\Response; 
 use React\Socket\SocketServer; 
 /* 
 * A class that provides authentication credentials to use the merchant API. 
 */ 
 class Authentication 
 { 
 private const SCOPE = 'https://www.googleapis.com/auth/content'; 
 private const AUTHORIZATION_URI = 'https://accounts.google.com/o/oauth2/v2/auth'; 
 private const OAUTH2_CALLBACK_IP_ADDRESS = '127.0.0.1'; 
 /** 
 * This method is called on each sample request, using either the service 
 * account or stored token.json file to get valid authentication 
 * credentials. 
 */ 
 public static function useServiceAccountOrTokenFile() 
 { 
 $config = Config::generateConfig(); 
 print "Attempting to load service account information." . PHP_EOL; 
 if (file_exists($config['serviceAccountFile'])) { 
 print 'Service account file exists, will use service account ' 
 . 'to authenticate.' 
 . PHP_EOL; 
 return $config['serviceAccountFile']; 
 } else { 
 print 'Service account file does not exist, attempting to load ' 
 . 'token file.' 
 . PHP_EOL; 
 // Check if the token file exists, and if so, return the contents of the file. Ensure 
 // you are running this code from the root directory of the PHP samples. 
 if (file_exists($config['tokenFile'])) { 
 // Read in the object of `refresh_token`, `client_secret` and 
 // `client_id` and cast it to an array. 
 $tokenJSON = (array) json_decode( 
 file_get_contents($config['tokenFile']) 
 ); 
 // Create OAuth credentials to be used in the merchant api 
 // client requests. 
 $credentials = new UserRefreshCredentials( 
 scope: null, 
 jsonKey: $tokenJSON 
 ); 
 print 'Token file exists, will use token file to authenticate.' 
 . PHP_EOL; 
 return $credentials; 
 } else { 
 print 'Token file does not exist, attempting to see if client ' 
 . 'secrets file exists.' 
 . PHP_EOL; 
 if (file_exists($config['clientSecretsFile'])) { 
 throw new Exception( 
 'Client secrets file exists, please run the ' 
 . '`GenerateUserCredentials example to use your client ' 
 . 'secrets to get OAuth2 refresh token. Then re-run your ' 
 . 'sample.' 
 . PHP_EOL 
 ); 
 } else { 
 throw new Exception( 
 'Service account file, token file, and client secrets ' 
 . 'file do not exist. Please follow the instructions in ' 
 . 'the top level ReadMe to create a service account or ' 
 . 'client secrets file.' 
 . PHP_EOL 
 ); 
 } 
 } 
 } 
 } 
 /** 
 * This function goes through the OAuth Flow with your client secrets 
 * to generate and store a token.json file to use for authentication. 
 */ 
 public static function generateUserCredentials(): void 
 { 
 $config = Config::generateConfig(); 
 print 'Token file does not exist, attempting to load client secrets ' 
 . 'file.' 
 . PHP_EOL; 
 if (file_exists($config['clientSecretsFile'])) { 
 print 'Client secrets file exists, will use client secrets to get ' 
 . 'an OAuth2 refresh token.' 
 . PHP_EOL; 
 if (!class_exists(HttpServer::class)) { 
 print 'Please install "react/http" package to be able to run ' 
 . 'this example'; 
 throw new Exception('Please install "react/http" package'); 
 } 
 // Creates a socket for localhost with random port. Port 0 is used 
 // to tell the SocketServer to create a server with a random port. 
 $socket = new SocketServer(self::OAUTH2_CALLBACK_IP_ADDRESS . ':0'); 
 // Ensure you've created a client secrets file in the appropriate 
 // location by following the instructions in the top level ReadMe. 
 // Remember that if you are using a web application, you need to add 
 // the following to its "Authorized redirect URIs": http://127.0.0.1 
 // in your GCP console (https://console.cloud.google.com/). 
 // Read the Client Secrets JSON file. 
 $json = file_get_contents($config['clientSecretsFile']); 
 // Decode the JSON file. 
 $json_data = json_decode($json, true); 
 $path = 'web'; 
 $redirectUrl = str_replace('tcp:', 'http:', $socket->getAddress()); 
 if(is_null($json_data[$path])){ 
 $path = 'installed'; 
 } 
 $oauth2 = new OAuth2( 
 [ 
 'clientId' => $json_data[$path]['client_id'], 
 'clientSecret' => $json_data[$path]['client_secret'], 
 'authorizationUri' => $json_data[$path]['auth_uri'], 
 'redirectUri' => $redirectUrl, 
 'tokenCredentialUri' => $json_data[$path]['token_uri'], 
 'scope' => self::SCOPE, 
 // Create a 'state' token to prevent request forgery. See 
 // https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken 
 // for details. 
 'state' => sha1(openssl_random_pseudo_bytes(1024)) 
 ] 
 ); 
 $authToken = null; 
 $server = new HttpServer( 
 function (ServerRequestInterface $request) use ($oauth2, &$authToken, $json_data) { 
 // Stops the server after tokens are retrieved. 
 if (!is_null($authToken)) { 
 Loop::stop(); 
 } 
 // Check if the requested path is the one set as the 
 // redirect URI. We add '/' here so the parse_url method 
 // can function correctly, since it cannot detect the URI 
 // without '/' at the end, which is the case for the value 
 // of getRedirectUri(). 
 if ( 
 $request->getUri()->getPath() 
 !== parse_url($oauth2->getRedirectUri() . '/', PHP_URL_PATH) 
 ) { 
 return new Response( 
 404, 
 ['Content-Type' => 'text/plain'], 
 'Page not found' 
 ); 
 } 
 // Exit if the state is invalid to prevent request forgery. 
 $state = $request->getQueryParams()['state']; 
 if (empty($state) || ($state !== $oauth2->getState())) { 
 throw new UnexpectedValueException( 
 "The state is empty or doesn't match the expected one." 
 . PHP_EOL 
 ); 
 }; 
 // Set the authorization code and fetch refresh and access 
 // tokens. 
 $code = $request->getQueryParams()['code']; 
 $oauth2->setCode($code); 
 $authToken = $oauth2->fetchAuthToken(); 
 $refreshToken = $authToken['refresh_token']; 
 print 'Your refresh token is: ' . $refreshToken . PHP_EOL; 
 print 'You can now run any example to automatically use ' 
 . 'your new refresh token to generate an access token and ' 
 . 'succesfully authenticate your request.' 
 . PHP_EOL; 
 $path = 'web'; 
 if(is_null($json_data[$path])){ 
 $path = 'installed'; 
 } 
 $token_file_credentials = [ 
 'client_id' => $json_data[$path]['client_id'], 
 'client_secret' => $json_data[$path]['client_secret'], 
 'refresh_token' => $refreshToken 
 ]; 
 file_put_contents( 
 "token.json", 
 json_encode($token_file_credentials) 
 ); 
 return new Response( 
 200, 
 ['Content-Type' => 'text/plain'], 
 'Your refresh token has been fetched. Check the ' 
 . 'console output for further instructions.' 
 ); 
 } 
 ); 
 $server->listen($socket); 
 printf( 
 'Log into the Google account you use for Google Ads and visit ' 
 . 'the following URL in your web browser: %1$s%2$s%1$s%1$s', 
 PHP_EOL, 
 implode( 
 [$oauth2->buildFullAuthorizationUri(['access_type' => 'offline']), '&prompt=consent'] 
 ) 
 ); 
 } else { 
 print 'Client secrets file does not exist. Please follow the ' 
 . 'instructions in the top level ReadMe to create a client secrets ' 
 . 'file.' 
 . PHP_EOL; 
 } 
 } 
 } 
  
 

Python

  # -*- coding: utf-8 -*- 
 # Copyright 2024 Google LLC 
 # 
 # Licensed under the Apache License, Version 2.0 (the "License"); 
 # you may not use this file except in compliance with the License. 
 # You may obtain a copy of the License at 
 # 
 #     http://www.apache.org/licenses/LICENSE-2.0 
 # 
 # Unless required by applicable law or agreed to in writing, software 
 # distributed under the License is distributed on an "AS IS" BASIS, 
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 # See the License for the specific language governing permissions and 
 # limitations under the License. 
 """This example will create credentials to use the Merchant API. 
 This file authenticates either via a provided service-account.json file, a 
 stored OAuth2 refresh token, or creates credentials and stores a refresh token 
 via a provided client-secrets.json file. 
 This example works with web OAuth client ID types. 
 https://console.cloud.google.com 
 IMPORTANT: For web app clients types, you must add "http://127.0.0.1" to the 
 "Authorized redirect URIs" list in your Google Cloud Console project before 
 running this example. 
 """ 
 import 
  
 hashlib 
 import 
  
 os 
 import 
  
 re 
 import 
  
 socket 
 import 
  
 sys 
 import 
  
 urllib.parse 
 from 
  
 examples.authentication 
  
 import 
 configuration 
 from 
  
 examples.authentication 
  
 import 
 token_storage 
 from 
  
 google.oauth2 
  
 import 
 service_account 
 # If using Web flow, the redirect URL must match exactly what’s configured in 
 # GCP for the OAuth client. 
 from 
  
 google_auth_oauthlib.flow 
  
 import 
 Flow 
 _SCOPE 
 = 
 "https://www.googleapis.com/auth/content" 
 _SERVER 
 = 
 "127.0.0.1" 
 _PORT 
 = 
 8080 
 _REDIRECT_URI 
 = 
 f 
 "http:// 
 { 
 _SERVER 
 } 
 : 
 { 
 _PORT 
 } 
 " 
 def 
  
 main 
 (): 
  
 """Generates OAuth2 credentials.""" 
 # Gets the configuration object that has the paths on the local machine to 
 # the `service-account.json`, `token.json`, and `client-secrets.json` files. 
 config 
 = 
 configuration 
 . 
 Configuration 
 () 
 . 
 get_config 
 () 
 service_account_path 
 = 
 config 
 [ 
 "service_account_path" 
 ] 
 print 
 ( 
 "Attempting to use service account credentials from " 
 f 
 " 
 { 
 service_account_path 
 } 
 ." 
 ) 
 if 
 os 
 . 
 path 
 . 
 isfile 
 ( 
 service_account_path 
 ): 
 print 
 ( 
 "Service account credentials found. Attempting to authenticate." 
 ) 
 credentials 
 = 
 service_account 
 . 
 Credentials 
 . 
 from_service_account_file 
 ( 
 service_account_path 
 , 
 scopes 
 = 
 [ 
 _SCOPE 
 ]) 
 return 
 credentials 
 else 
 : 
 print 
 ( 
 "Service account credentials not found." 
 ) 
 full_token_path 
 = 
 os 
 . 
 path 
 . 
 join 
 ( 
 os 
 . 
 getcwd 
 (), 
 config 
 [ 
 "token_path" 
 ]) 
 print 
 ( 
 f 
 "Attempting to use stored token data from 
 { 
 full_token_path 
 } 
 " 
 ) 
 if 
 os 
 . 
 path 
 . 
 isfile 
 ( 
 config 
 [ 
 "token_path" 
 ]): 
 print 
 ( 
 "Token file found." 
 ) 
 print 
 ( 
 "Attempting to use token file to authenticate" 
 ) 
 return 
 get_credentials_from_token 
 ( 
 config 
 ) 
 else 
 : 
 print 
 ( 
 "Token file not found." 
 ) 
 client_secrets_path 
 = 
 config 
 [ 
 "client_secrets_path" 
 ] 
 print 
 ( 
 f 
 "Attempting to use client secrets from 
 { 
 client_secrets_path 
 } 
 ." 
 ) 
 if 
 os 
 . 
 path 
 . 
 isfile 
 ( 
 client_secrets_path 
 ): 
 print 
 ( 
 "Client secrets file found." 
 ) 
 print 
 ( 
 "Attempting to use client secrets to authenticate" 
 ) 
 return 
 get_credentials_from_client_secrets 
 ( 
 config 
 ) 
 else 
 : 
 print 
 ( 
 "Service account file, token file, and client secrets " 
 "file do not exist. Please follow the instructions in " 
 "the top level ReadMe to create a service account or " 
 "client secrets file." 
 ) 
 exit 
 ( 
 1 
 ) 
 def 
  
 get_credentials_from_token 
 ( 
 config 
 ): 
  
 """Generates OAuth2 refresh token from stored local token file.""" 
 credentials 
 = 
 token_storage 
 . 
 Storage 
 ( 
 config 
 , 
 [ 
 _SCOPE 
 ]) 
 . 
 get 
 () 
 return 
 credentials 
 def 
  
 get_credentials_from_client_secrets 
 ( 
 config 
 ): 
  
 """Generates OAuth2 refresh token using the Web application flow. 
 To retrieve the necessary client_secrets JSON file, first 
 generate OAuth 2.0 credentials of type Web application in the 
 Google Cloud Console (https://console.cloud.google.com). 
 Make sure "http://_SERVER:_PORT" is included the list of 
 "Authorized redirect URIs" for this client ID." 
 Starts a basic server and initializes an auth request. 
 Args: 
 config: an instance of the Configuration object. 
 Returns: 
 Credentials used to authenticate with the Merchant API. 
 """ 
 # A list of API scopes to include in the auth request, see: 
 # https://developers.google.com/identity/protocols/oauth2/scopes 
 scopes 
 = 
 [ 
 _SCOPE 
 ] 
 # A path to where the client secrets JSON file is located 
 # on the machine running this example. 
 client_secrets_path 
 = 
 config 
 [ 
 "client_secrets_path" 
 ] 
 flow 
 = 
 Flow 
 . 
 from_client_secrets_file 
 ( 
 client_secrets_path 
 , 
 scopes 
 = 
 scopes 
 ) 
 flow 
 . 
 redirect_uri 
 = 
 _REDIRECT_URI 
 # Create an anti-forgery state token as described here: 
 # https://developers.google.com/identity/protocols/OpenIDConnect#createxsrftoken 
 passthrough_val 
 = 
 hashlib 
 . 
 sha256 
 ( 
 os 
 . 
 urandom 
 ( 
 1024 
 )) 
 . 
 hexdigest 
 () 
 authorization_url 
 , 
 state 
 = 
 flow 
 . 
 authorization_url 
 ( 
 access_type 
 = 
 "offline" 
 , 
 state 
 = 
 passthrough_val 
 , 
 prompt 
 = 
 "consent" 
 , 
 include_granted_scopes 
 = 
 "true" 
 , 
 ) 
 print 
 ( 
 f 
 "Your state token is: 
 { 
 state 
 } 
 \n 
 " 
 ) 
 # Prints the authorization URL so you can paste into your browser. In a 
 # typical web application you would redirect the user to this URL, and they 
 # would be redirected back to "redirect_url" provided earlier after 
 # granting permission. 
 print 
 ( 
 "Paste this URL into your browser: " 
 ) 
 print 
 ( 
 authorization_url 
 ) 
 print 
 ( 
 f 
 " 
 \n 
 Waiting for authorization and callback to: 
 { 
 _REDIRECT_URI 
 } 
 " 
 ) 
 # Retrieves an authorization code by opening a socket to receive the 
 # redirect request and parsing the query parameters set in the URL. 
 code 
 = 
 urllib 
 . 
 parse 
 . 
 unquote 
 ( 
 get_authorization_code 
 ( 
 passthrough_val 
 )) 
 # Passes the code back into the OAuth module to get a refresh token. 
 flow 
 . 
 fetch_token 
 ( 
 code 
 = 
 code 
 ) 
 refresh_token 
 = 
 flow 
 . 
 credentials 
 . 
 refresh_token 
 print 
 ( 
 f 
 " 
 \n 
 Your refresh token is: 
 { 
 refresh_token 
 } 
 \n 
 " 
 ) 
 # Stores the provided credentials into the appropriate file. 
 storage 
 = 
 token_storage 
 . 
 Storage 
 ( 
 config 
 , 
 scopes 
 ) 
 storage 
 . 
 put 
 ( 
 flow 
 . 
 credentials 
 ) 
 return 
 flow 
 . 
 credentials 
 def 
  
 get_authorization_code 
 ( 
 passthrough_val 
 ): 
  
 """Opens a socket to handle a single HTTP request containing auth tokens. 
 Args: 
 passthrough_val: an anti-forgery token used to verify the request 
 received by the socket. 
 Returns: 
 a str access token from the Google Auth service. 
 """ 
 # Opens a socket at _SERVER:_PORT and listen for a request. 
 sock 
 = 
 socket 
 . 
 socket 
 () 
 sock 
 . 
 setsockopt 
 ( 
 socket 
 . 
 SOL_SOCKET 
 , 
 socket 
 . 
 SO_REUSEADDR 
 , 
 1 
 ) 
 sock 
 . 
 bind 
 (( 
 _SERVER 
 , 
 _PORT 
 )) 
 sock 
 . 
 listen 
 ( 
 1 
 ) 
 connection 
 , 
 address 
 = 
 sock 
 . 
 accept 
 () 
 print 
 ( 
 f 
 "Socket address: 
 { 
 address 
 } 
 " 
 ) 
 data 
 = 
 connection 
 . 
 recv 
 ( 
 1024 
 ) 
 # Parses the raw request to retrieve the URL query parameters. 
 params 
 = 
 parse_raw_query_params 
 ( 
 data 
 ) 
 try 
 : 
 if 
 not 
 params 
 . 
 get 
 ( 
 "code" 
 ): 
 # If no code is present in the query params then there will be an 
 # error message with more details. 
 error 
 = 
 params 
 . 
 get 
 ( 
 "error" 
 ) 
 message 
 = 
 f 
 "Failed to retrieve authorization code. Error: 
 { 
 error 
 } 
 " 
 raise 
 ValueError 
 ( 
 message 
 ) 
 elif 
 params 
 . 
 get 
 ( 
 "state" 
 ) 
 != 
 passthrough_val 
 : 
 message 
 = 
 "State token does not match the expected state." 
 raise 
 ValueError 
 ( 
 message 
 ) 
 else 
 : 
 message 
 = 
 "Authorization code was successfully retrieved." 
 except 
 ValueError 
 as 
 error 
 : 
 print 
 ( 
 error 
 ) 
 sys 
 . 
 exit 
 ( 
 1 
 ) 
 finally 
 : 
 response 
 = 
 ( 
 "HTTP/1.1 200 OK 
 \n 
 " 
 "Content-Type: text/html 
 \n\n 
 " 
 f 
 "<b> 
 { 
 message 
 } 
< /b>" 
 "<p>Please check the console output.</p> 
 \n 
 " 
 ) 
 connection 
 . 
 sendall 
 ( 
 response 
 . 
 encode 
 ()) 
 connection 
 . 
 close 
 () 
 return 
 params 
 . 
 get 
 ( 
 "code" 
 ) 
 def 
  
 parse_raw_query_params 
 ( 
 data 
 ): 
  
 """Parses a raw HTTP request to extract its query params as a dict. 
 Note that this logic is likely irrelevant if you're building OAuth logic 
 into a complete web application, where response parsing is handled by a 
 framework. 
 Args: 
 data: raw request data as bytes. 
 Returns: 
 a dict of query parameter key value pairs. 
 """ 
 # Decodes the request into a utf-8 encoded string. 
 decoded 
 = 
 data 
 . 
 decode 
 ( 
 "utf-8" 
 ) 
 # Uses a regular expression to extract the URL query parameters string. 
 match 
 = 
 re 
 . 
 search 
 ( 
 r 
 "GET\s\/\?(.*) " 
 , 
 decoded 
 ) 
 if 
 not 
 match 
 : 
 return 
 {} 
 params 
 = 
 match 
 . 
 group 
 ( 
 1 
 ) 
 # Splits the parameters to isolate the key/value pairs. 
 pairs 
 = 
 [ 
 pair 
 . 
 split 
 ( 
 "=" 
 ) 
 for 
 pair 
 in 
 params 
 . 
 split 
 ( 
 "&" 
 )] 
 # Converts pairs to a dict to make it easy to access the values. 
 return 
 { 
 key 
 : 
 val 
 for 
 key 
 , 
 val 
 in 
 pairs 
 } 
  
 
Design a Mobile Site
View Site in Mobile | Classic
Share by: