Re: Trying to migrate .NET/C# application to OAuth 2.0, Service Account, keep getting "access_denied"

1,461 views
Skip to first unread message
Message has been deleted

Danial Klimkin

unread,
Jan 10, 2013, 4:15:15 AM1/10/13
to adwor...@googlegroups.com
Hello,


The error you are receiving is not an AdWords API error but OAuth2.0 error.

First of all, you don't want to provide OAuth2ClientId and OAuth2ClientSecret for JWT auth, try removing it. If you still get the same error, send me a screenshot of the Console with this project / key over *email* (not to the group).


-Danial, AdWords API Team.



On Saturday, January 5, 2013 4:56:38 AM UTC+4, sandm...@gmail.com wrote:

I work for a company that uses Google AdWords, and we have a .NET application (written in C#) that makes use of the Google AdWords API. We are using the latest version (201209) of the Google API client assemblies for .NET. The application currently uses the ClientLogin protocol for authenticating, but we are trying to migrate to OAuth 2.0.

I am fairly confident that I have gone through all of the required steps to be able to successfully negotiate a request for an authentication token. I am using the sample code solution that comes with the Google API client assemblies in order to test this, using the “Service Account” workflow. So far I have not succeeded. Within the code we call the GenerateAccessTokenForServiceAccount() method of the OAuth2Provider object that is the OAuthProvider property of an AdWordsUser object. The result is that a Google.Api.Ads.Common.Lib.AdsOAuthException is thrown with the message “Failed to get access to token for service account” that also includes a JSON object with one key-value pair:

“error” : “access_denied”

When examining the traffic using Fiddler2, I see what looks like a properly-formed request going out, according to the relevant documentation (https://developers.google.com/accounts/docs/OAuth2ServiceAccount) …

POST https://accounts.google.com/o/oauth2/token HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Host: accounts.google.com

Content-Length: 583

Expect: 100-continue

Connection: Keep-Alive

 

grant_type=urn%3aietf%3aparams%3aoauth%3agrant-type%3ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIzNDgzMjEzMjIyNDlAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCAic2NvcGUiOiJodHRwczovL2Fkd29yZHMuZ29vZ2xlLmNvbS9hcGkvYWR3b3Jkcy8iLCAiYXVkIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL3Rva2VuIiwgImV4cCI6MTM1NzMzMTIxNSwgImlhdCI6MTM1NzMyNzYxNSwgInBybiI6IkluZm9zcGFjZUNvcnBAZ21haWwuY29tIn0.BnD3-oPozaUInI9LexIF_wqNnIOLeGLBfv1oJOjzpHjc9q5p_-Q7A7i_V3QkqCKgV2EmWT3wU8BNUKj7YrpKThWgzKNT661uA4HiF2ZPQNYduKxouJrB7OON9BXoWBdgkSjyWb5frEzTmzklM476SEQAJvWP2djxBSGaha3Qwww

… and a HTTP 400 response coming back that contains no meaningful header information, and the aforementioned JSON object in the body.

HTTP/1.1 400 Bad Request

Cache-Control: no-cache, no-store, max-age=0, must-revalidate

Pragma: no-cache

Expires: Fri, 01 Jan 1990 00:00:00 GMT

Date: Fri, 04 Jan 2013 19:26:54 GMT

Content-Type: application/json

X-Content-Type-Options: nosniff

X-Frame-Options: SAMEORIGIN

X-XSS-Protection: 1; mode=block

Server: GSE

Content-Length: 31

 

{

  "error" : "access_denied"

}

I am not sure what that response means. From what I’ve seen of other failed attempts described here and on other forums, I am assuming that the request is correctly formed and would normally succeed, but there is something in how the client access credentials are set up on the API console that is wrong enough to prevent an authentication token from being granted.

What follows is a step-by-step description of every step taken, from requesting the developer token to “access_denied”. It is my expectation that others who have gone before and succeeded will be able to identify whatever missteps I have made and offer sufficient information to get me past “access_denied”.

1.       Using a Google AdWords MCC account, requested a developer token at the AdWords API Center. This request has been approved, and a developer token supplied.

2.       For the same MCC account, logged in to the Google API Console (https://code.google.com/apis/console) and created a project (“API Project”). We did not register for a Project ID.

3.       On the Services tab, we did not set up or activate any services. AdWords is not listed. According to the AdWords API documentation (https://developers.google.com/adwords/api/docs/authentication), this step can be skipped.

4.       On the “API Access” tab of this project, we entered branding information and set up a Client ID for a Service account. This generated a “client ID” for a service account which had

a.       a Client ID (012345678901.apps.googleusercontent.com)

b.      an e-mail address (012345678901@developer.gserviceaccount.com)

c.       a public key fingerprint (forty hexadecimal digits)

d.      a private/public key (.P12 file), which we downloaded

5.       I unzipped the code samples from the Google API client archive (awapi_dotnet_lib_15.2.0.zip) and opened the solution in Visual Studio 2012. I set the ConsoleTest project as the start project.

6.       I uncommented and edited the relevant key-value pairs in the configuration file to set up the sample application to use the access credentials we had generated earlier.

  <AdWordsApi>

    <!-- Fill the header values. -->

    <add key="UserAgent" value="Our_Application_Name"/>

    <add key="DeveloperToken" value="hyP0tH3t1c47D3v370p3Rt0k3N"/>

    <add key="ClientCustomerId" value="123-456-7890"/>

    <!-- To use OAuth2 as authentication mechanism, uncomment the following section and comment the AuthToken and OAuth2 sections. -->

    <add key="AuthorizationMethod" value="OAuth2" />

    <!-- Use the following keys if you want to use client id and client secret.-->

    <add key="OAuth2ClientId" value="012345678901.apps.googleusercontent.com" />

    <add key="OAuth2ClientSecret" value="0123456789abcdef0123456789abcdef01234567" />

    <!-- Use the following keys if you want to use a service account. -->

    <add key="OAuth2ServiceAccountEmail"

        value="012345...@developer.gserviceaccount.com" />

    <add key="OAuth2PrnEmail" value="OurAdWordsMccAccountXYZ@gmail.com" />

    <add key="OAuth2JwtCertificatePath"

        value="C:\local_file_path\0123456789abcdef0123456789abcdef01234567-privatekey.p12" />

    <add key="OAuth2JwtCertificatePassword" value="super_secret_password" />

  </AdWordsApi>

 

7.       In all cases, I’ve provided sample values rather than actual values. The ClientCustomerId value is actually the Customer ID of our Adwords MCC account. The OAuth2PrnEmail is the e-mail address of that account.

8.       Even if the scope key-value pair isn’t set in the configuration file, the scope property in the AdWordsUser’s configuration does get set to the correct value for AdWords read/write access (https://adwords.google.com/api/adwords/) before an authentication token is requested. This is done by the call to AdWordsService.GetOAuthScope() in the first line of the method below.

9.       In the sample console application from Google, the exception is thrown in the DoAuth2AuthorizationForServiceAccounts() method of the Program class in the code file Program.cs . The highlighted line is where the exception is thrown.

<span style="background: white; co...
Show original

Danial Klimkin

unread,
Jan 17, 2013, 3:32:38 AM1/17/13
to adwor...@googlegroups.com
Hello All,


The JWT authorization is only available for domain administrators. It requires you to grant the service account permissions to act on users' behalf when interacting with AdWords API. As the result, you can not use this scheme with @gmail accounts.

If you still want to use service accounts, assuming you have or have signed up for a Google Apps Domain, you need to do the following:

In your Google Apps Domain cpanel, go to (replace YOUR_DOMAIN with your domain, like google.com for example):


you need to add your client ID (not email address) from the Google API Console for your serviced account with the scope:

  https://adwords.google.com/api/adwords/

If you use a public account, like the one on gmail, please use the non-JWT OAuth2.0 authentication protocol.


-Danial, AdWords API Team.

/// <summary>

/// Does the OAuth2 authorization for service accounts.

/// </summary>

/// <param name="user">The AdWords user.</param>

private static void DoAuth2AuthorizationForServiceAccounts(AdWordsUser user)

{

    user.Config.OAuth2Scope = AdWordsService.GetOAuthScope(user.Config as AdWordsAppConfig);

 

    OAuth2Provider oAuth2 = new OAuth2Provider(user.Config);

    user.OAuthProvider = oAuth2;

    oAuth2.GenerateAccessTokenForServiceAccount();

}

 

That is the call that is supposed to get the authentication token from the AdWords API.

So far, in my investigations, in this forum and others, and in web searches, I have not yet seen an accounting from any other AdWords API user whose authentication requests have ended with the “access_denied” result, much less any advice on what to do when that happens. I have seen examples from people who have written their own code to generate a JWT and request authentication tokens, and I have seen inferences that one must activate at least one other Google API service in the API Console project before one can access the AdWords API. We would prefer to conduct all AdWords API operations through the API client assemblies that Google supplies, and would prefer not to associate our API client information with another API service, even if we don’t ever make use of it.

sandm...@gmail.com

unread,
Apr 8, 2013, 1:58:47 PM4/8/13
to adwor...@googlegroups.com
Sorry for not replying. I am no longer with the group that was working the initial problem; I'm not working on it any more. I have no idea whether they eventually got it to work.

On Monday, March 25, 2013 3:10:27 PM UTC-7, Claus Pedersen wrote:
Did you manage to get this to work?

I have the same problem and can't figure out how to solve it.

I have followed the steps above for out Apps domain.

/Claus
Reply all
Reply to author
Forward
0 new messages