Re: How do I authenticate to send a clickConversion to google Ads with a service account and over REST API with typescript

2024-01-31 Thread Bjoern Ammon
This error appears in python
RefreshError: ('unauthorized_client: Client is unauthorized to retrieve 
access tokens using this method, or client not authorized for any of the 
scopes requested.', {'error': 'unauthorized_client', 'error_description': 
'Client is unauthorized to retrieve access tokens using this method, or 
client not authorized for any of the scopes requested.'})
Bjoern Ammon schrieb am Mittwoch, 31. Januar 2024 um 10:47:11 UTC+1:

> Addition: 
> The error i receive comes with authentication to googleapis
> [image: IIF1Y.png]
>
> Bjoern Ammon schrieb am Mittwoch, 31. Januar 2024 um 10:20:35 UTC+1:
>
>> I've tried with this documentation 
>> <https://developers.google.com/google-ads/api/rest/auth> authenticate 
>> and with this REST 
>> <https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadClickConversions>
>>  to 
>> send the conversion over REST API due to missing 
>> Typescript/Javascript-Client-Bib. 
>>
>> *My error:* 
>> error: invalid_client 
>> error_description: Unauthorized
>>
>> *My setup:* 
>> Regarding to the documentation I have a google ads account with a 
>> developer token. This token will be used, when I send the click conversion, 
>> as you can see here 
>> <https://developers.google.com/google-ads/api/rest/auth#request_headers>. 
>> The token has nothing to do with the authentication of the service account. 
>> Therefore I have a service account on the Google Cloud Project, which also 
>> has the Google Ads Api enabled.[image: Ii3VN.png]
>>
>> I also added to the workspace domain to the domain wide delegation the 
>> client id of the service account with the scope 
>>
>> *https://www.googleapis.com/auth/adwords 
>> <https://www.googleapis.com/auth/adwords>[image: W0d6l.png][image: 
>> pB83U.png]*
>>
>> The clientIds are fitting as well.
>>
>> Just in case I also added an OAuth consent screen with the scope 
>> *https://www.googleapis.com/auth/adwords 
>> <https://www.googleapis.com/auth/adwords>* with the Testing status and 
>> external. But I don't think I will need this with a service account.
>>
>> The service account itself has no further related rights. The 
>> documentation don't give me the info, that the service account need further 
>> rights. My thoughts: I added the client id to the domain wide delegation, 
>> this should be enough. I hope I am wrong here.
>>
>> Now everything should be set up. I hope I didn't miss a step.
>>
>> *My guess:* Either I am missing some rights. Or I missunderstand the 
>> refresh token in the function authenticateToGoogleAdsManager. I create a 
>> signed JWT. Google says here, I need a refresh token. But the 
>> authentication via await fetch('https://oauth2.googleapis.com/token' just 
>> gives me an access token. So I thought I just need a jwt here.
>>
>> This is the way I am executing my code (in a testcase. Service Account 
>> JSON and clickConversion are given.)
>>
>> *My code to understand what i do (I suggest to check my Question on 
>> Stackoverflow 
>> <https://stackoverflow.com/questions/77833488/how-do-i-authenticate-to-send-a-clickconversion-to-google-ads-with-a-service-acc>
>>  
>> to read the codeblock) *
>>
>> ```
>> // First I create a signed jwt 
>> const jwt = generateJsonWebTokenForServiceAccount( serviceAccount, ['
>> https://www.googleapis.com/auth/adwords'], 'googleads' ) 
>>
>> // Then I use the signed jwt to authenticate to Google Ads Manager 
>> const authenticationResult = await authenticateToGoogleAdsManager( 
>> serviceAccount.client_id, serviceAccount.private_key, jwt )
>>
>> // Then I use the access token to send a click conversion to Google Ads 
>> Manager 
>> const test = await sendClickConversionToGoogleAdsManager( CUSTOMERID, 
>> clickConversion, accessToken.access_token, 'DEV-TOKEN' )
>>
>>
>> Here are the functions: 
>> /** * Generates a JSON Web Token (JWT) for a service account. * * @param 
>> serviceAccount - The service account object containing the client email 
>> and private key. * @param scopes - An array of scopes for which the 
>> token will be authorized. * @param serviceName - The name of the service 
>> for which the token will be authorized. Default is 'oauth2'. * @param 
>> expirationTimeInSeconds - The expiration time of the token in seconds. 
>> Default is 3600 seconds (1 hour). * @returns The generate

Re: How do I authenticate to send a clickConversion to google Ads with a service account and over REST API with typescript

2024-01-31 Thread Bjoern Ammon
Addition: 
The error i receive comes with authentication to googleapis
[image: IIF1Y.png]

Bjoern Ammon schrieb am Mittwoch, 31. Januar 2024 um 10:20:35 UTC+1:

> I've tried with this documentation 
> <https://developers.google.com/google-ads/api/rest/auth> authenticate and 
> with this REST 
> <https://developers.google.com/google-ads/api/rest/reference/rest/v15/customers/uploadClickConversions>
>  to 
> send the conversion over REST API due to missing 
> Typescript/Javascript-Client-Bib. 
>
> *My error:* 
> error: invalid_client 
> error_description: Unauthorized
>
> *My setup:* 
> Regarding to the documentation I have a google ads account with a 
> developer token. This token will be used, when I send the click conversion, 
> as you can see here 
> <https://developers.google.com/google-ads/api/rest/auth#request_headers>. 
> The token has nothing to do with the authentication of the service account. 
> Therefore I have a service account on the Google Cloud Project, which also 
> has the Google Ads Api enabled.[image: Ii3VN.png]
>
> I also added to the workspace domain to the domain wide delegation the 
> client id of the service account with the scope 
>
> *https://www.googleapis.com/auth/adwords 
> <https://www.googleapis.com/auth/adwords>[image: W0d6l.png][image: 
> pB83U.png]*
>
> The clientIds are fitting as well.
>
> Just in case I also added an OAuth consent screen with the scope 
> *https://www.googleapis.com/auth/adwords 
> <https://www.googleapis.com/auth/adwords>* with the Testing status and 
> external. But I don't think I will need this with a service account.
>
> The service account itself has no further related rights. The 
> documentation don't give me the info, that the service account need further 
> rights. My thoughts: I added the client id to the domain wide delegation, 
> this should be enough. I hope I am wrong here.
>
> Now everything should be set up. I hope I didn't miss a step.
>
> *My guess:* Either I am missing some rights. Or I missunderstand the 
> refresh token in the function authenticateToGoogleAdsManager. I create a 
> signed JWT. Google says here, I need a refresh token. But the 
> authentication via await fetch('https://oauth2.googleapis.com/token' just 
> gives me an access token. So I thought I just need a jwt here.
>
> This is the way I am executing my code (in a testcase. Service Account 
> JSON and clickConversion are given.)
>
> *My code to understand what i do (I suggest to check my Question on 
> Stackoverflow 
> <https://stackoverflow.com/questions/77833488/how-do-i-authenticate-to-send-a-clickconversion-to-google-ads-with-a-service-acc>
>  
> to read the codeblock) *
>
> ```
> // First I create a signed jwt 
> const jwt = generateJsonWebTokenForServiceAccount( serviceAccount, ['
> https://www.googleapis.com/auth/adwords'], 'googleads' ) 
>
> // Then I use the signed jwt to authenticate to Google Ads Manager 
> const authenticationResult = await authenticateToGoogleAdsManager( 
> serviceAccount.client_id, serviceAccount.private_key, jwt )
>
> // Then I use the access token to send a click conversion to Google Ads 
> Manager 
> const test = await sendClickConversionToGoogleAdsManager( CUSTOMERID, 
> clickConversion, accessToken.access_token, 'DEV-TOKEN' )
>
>
> Here are the functions: 
> /** * Generates a JSON Web Token (JWT) for a service account. * * @param 
> serviceAccount - The service account object containing the client email 
> and private key. * @param scopes - An array of scopes for which the token 
> will be authorized. * @param serviceName - The name of the service for 
> which the token will be authorized. Default is 'oauth2'. * @param 
> expirationTimeInSeconds - The expiration time of the token in seconds. 
> Default is 3600 seconds (1 hour). * @returns The generated JSON Web 
> Token. */ export function generateJsonWebTokenForServiceAccount( 
> serviceAccount: ServiceAccount, scopes: string[], serviceName: string = 
> 'oauth2', expirationTimeInSeconds = 3600 ) { const aud = serviceName === 
> 'oauth2' ? 'https://oauth2.googleapis.com/token' : `https://${serviceName}
> .googleapis.com/` <http://googleapis.com/> const currentTimestamp = Math.
> floor(Date.now() / 1000) const expirationTimestamp = currentTimestamp + 
> expirationTimeInSeconds const payload = { iss: serviceAccount.client_email, 
> sub: serviceAccount.client_email, scope: scopes.join(' '), aud: aud, exp: 
> expirationTimestamp, iat: currentTimestamp } const options: SignOptions = 
> { algorithm: 'RS256' } return jwt.sign(payload, serviceAccount.private