Using OAuth2 - jimper/googleads-dotnet-lib GitHub Wiki

Introduction

All the Ads APIs use OAuth 2.0 as its authentication mechanism. This wiki article explains how to add OAuth support for your Ads API application when using Ads API .NET client libraries. Note that the code shows how this is done for AdWordsUser and AdWordsAppConfig, but the code is similar for other APIs. (e.g. DfpUser and DfpAppConfig).

Get your OAuth2 Client id and secret

You need to create an OAuth2 client id and secret to make API calls using OAuth2 authentication mechanism. Refer to this wiki article for details on how to create one.

Adding OAuth2 support for your application (single login)

If your application manages only one Advertiser account (or a hierarchy of Advertiser accounts all linked under a single master MCC), then you don’t need to build OAuth2 flow into your application. You can instead use a utility named OAuth2TokenGenerator.exe to generate the necessary OAuth2 configuration. Refer to this wiki article for generating OAuth2 configuration using OAuth2TokenGenerator.

Adding OAuth2 support for your application (multiple logins)

If you manage multiple unrelated AdWords accounts, then you need to build OAuth2 sign-in flow into your application as part of adding OAuth2 support for your application. You can skip to an appropriate section below, depending on whether your application is a web application, or a desktop application.

Adding OAuth2 support to your ASP.NET application

Adding OAuth2 support to your ASP.NET application involves three steps:

  • Obtain an OAuth2 clientId and clientSecret from the Google Developers Console.
  • Write an OAuth2 callback page and register it as a valid OAuth2 callback URL.
  • Configure your AdsUser instance to use OAuth2.

1. Obtain an OAuth2 clientId and clientSecret from the Google Developers Console.

You need to follow the instructions in this wiki article to obtain an OAuth2 client id and secret. In your application’s web.config, substitute these values for the OAuth2ClientId and OAuth2ClientSecret settings.

<add key="AuthorizationMethod" value="OAuth2" />
<add key="OAuth2ClientId" value="INSERT_OAUTH2_CLIENT_ID_HERE" />
<add key="OAuth2ClientSecret" value="INSERT_OAUTH2_CLIENT_SECRET_HERE" />
<add key="OAuth2Mode" value="APPLICATION" />

2. Write an OAuth2 callback page and register it as a valid OAuth2 callback URL

If you are using web flow for OAuth2, then you need to add a page to your web application to handle OAuth2 callbacks. The URL of this page should be added to "Redirect URIs" on the Google Developers Console page. You should also provide this URL as the value for the OAuth2RedirectUri setting in your application’s web.config.

This page should be able to handle two cases:

  • If any other page in your website detects that the user hasn't authorized your application to make API calls, then it needs to redirect the user to this page. The page needs to construct an Authorization Url and redirect the user to the Google OAuth2 server.
  • Once the user has authorized your application, Google OAuth2 servers will redirect the user back to this page. The page needs to use the OAuth2 authorizationCode to obtain an access token and optionally a refresh token. Then it needs to redirect the user back to the page the user originally came from. The page should also have an appropriate mechanism to share the Access and Refresh tokens between multiple pages (e.g. session, persistent store like database, etc.)

OAuth2 provides a parameter named State to allow you to distinguish between the two flows. The following code snippet uses this parameter to distinguish between the two use cases. When your app calls the callback page, the State parameter won't be set. The State parameter will be set when the Google OAuth2 servers call your callback page. Also, we will use Session to pass the parameters between the different pages.

protected void Page_Load(object sender, EventArgs e) {
  // Create an AdWordsAppConfig object with the default settings in
  // App.config.
  AdWordsAppConfig config = new AdWordsAppConfig();
  if (config.AuthorizationMethod == AdWordsAuthorizationMethod.OAuth2) {
    if (config.OAuth2Mode == OAuth2Flow.APPLICATION &&
        string.IsNullOrEmpty(config.OAuth2RefreshToken)) {
      DoAuth2Configuration(config);
    }
  }
}

private void DoAuth2Configuration(AdWordsAppConfig config) {
  // Since we use this page for OAuth callback also, we set the callback
  // url as the current page. For a non-web application, this will be null.
  config.OAuth2RedirectUri = Request.Url.GetLeftPart(UriPartial.Path);

  // Create an OAuth2 object for handling OAuth2 flow.
  OAuth2ProviderForApplications oAuth =
      new OAuth2ProviderForApplications(config);

  if (Request.Params["state"] == null) {
    // This is the first time this page is being loaded.
    // Set the state variable to any value that helps you recognize
    // when this url will be called by the OAuth2 server.
    oAuth.State = "callback";

    // Create an authorization url and redirect the user to that page.
    Response.Redirect(oAuth.GetAuthorizationUrl());
  } else if (Request.Params["state"] == "callback") {
    // This page was loaded because OAuth server did a callback.
    // Retrieve the authorization code from the url and use it to fetch
    // the access token. This call will also fetch the refresh token if
    // your mode is offline.
    oAuth.FetchAccessAndRefreshTokens(Request.Params["code"]);

    // Save the OAuth2 provider for future use. If you wish to save only
    // the values and restore the object later, then save
    // oAuth.RefreshToken, oAuth.AccessToken, oAuth.UpdatedOn and
    // oAuth.ExpiresIn.
    //
    // You can later restore the values as
    // AdWordsUser user = new AdWordsUser();
    // user.Config.OAuth2Mode = OAuth2Flow.APPLICATION;
    // OAuth2ProviderForApplications oAuth =
    //     (user.OAuthProvider as OAuth2ProviderForApplications);
    // oAuth.RefreshToken = xxx;
    // oAuth.AccessToken = xxx;
    // oAuth.UpdatedOn = xxx;
    // oAuth.ExpiresIn = xxx;
    //
    // Note that only oAuth.RefreshToken is mandatory. If you leave
    // oAuth.AccessToken as empty, or if oAuth.UpdatedOn + oAuth.ExpiresIn
    // is in the past, the access token will be refreshed by the library.
    // You can listen to this event as
    //
    // oAuth.OnOAuthTokensObtained += delegate(AdsOAuthProvider provider) {
    //    OAuth2ProviderForApplications oAuth =
    //        (provider as OAuth2ProviderForApplications);
    //    // Save oAuth.RefreshToken, oAuth.AccessToken, oAuth.UpdatedOn and
    //    // oAuth.ExpiresIn.
    //};
    Session["OAuthProvider"] = oAuth;
    // Redirect the user to the main page.
    Response.Redirect("Default.aspx");
  } else {
    throw new Exception("Unknown state for OAuth callback.");
  }
}

3. Configure your AdsUser to use OAuth2

The final step is to configure your AdsUser object to use OAuth2. The code snippet to do this is shown below.

private void ConfigureUserForOAuth() {
  AdWordsAppConfig config = (user.Config as AdWordsAppConfig);
  if (config.AuthorizationMethod == AdWordsAuthorizationMethod.OAuth2) {
    user.OAuthProvider =
        (OAuth2ProviderForApplications) Session["OAuthProvider"];
    if (user.OAuthProvider == null) {
      Response.SendRedirect("OAuthLogin.aspx");
    }
  } else {
    throw new Exception("Authorization mode is not OAuth.");
  }
}

You can now make calls to Ads API as usual.

Adding OAuth2 support to your desktop application

Adding OAuth2 support to your desktop application is similar to the process for ASP.NET applications, except that you won’t have an OAuth callback page. You need to ask your users to open the Authorization Url in a web browser, authorize the application and provide the authorizationCode. The following code shows how this is done for a console application:

public class ConsoleExample {
  static void Main(string[] args) {
    AdWordsUser user = new AdWordsUser();
    DoAuth2Authorization(user);
       
    // Make your API calls.
  }

  private static void DoAuth2Authorization(AdWordsUser user) {
    // Since we are using a console application, set the callback url to null.
    user.Config.OAuth2RedirectUri = null;
    AdsOAuthProviderForApplications oAuth2Provider =
        (user.OAuthProvider as AdsOAuthProviderForApplications);
    // Get the authorization url.
    string authorizationUrl = oAuth2Provider.GetAuthorizationUrl();
    Console.WriteLine("Open a fresh web browser and navigate to \n\n{0}\n\n. You will be " +
        "prompted to login and then authorize this application to make calls to the " +
        "AdWords API. Once approved, you will be presented with an authorization code.",
        authorizationUrl);

    // Accept the OAuth2 authorization code from the user.
    Console.Write("Enter the authorization code :");
    string authorizationCode = Console.ReadLine();
  
    // Fetch the access and refresh tokens.
    oAuth2Provider.FetchAccessAndRefreshTokens(authorizationCode);
  }
}

If you don’t want your users to leave your application, you could embed a WebBrowser in your application to capture the OAuth2 authorizationCode. You can refer to the source code for OAuth2TokenGenerator application for a code example.

Using OAuth2 service accounts

OAuth2 provides a mechanism called service accounts that allows you to obtain OAuth tokens without ANY user intervention. However, using this configuration involves a considerable number of steps. You can refer to https://developers.google.com/adwords/api/docs/guides/service-accounts for details. Once you follow the instructions in the service account guide, you need to configure the following keys in your App.config / Web.config.

<add key="OAuth2Mode" value="SERVICE_ACCOUNT" />
<add key="OAuth2ServiceAccountEmail" value="INSERT_OAUTH2_SERVICE_ACCOUNT_EMAIL_HERE" />
<add key="OAuth2PrnEmail" value="INSERT_OAUTH2_USER_EMAIL_HERE" />
<add key="OAuth2JwtCertificatePath" value="INSERT_OAUTH2_JWT_CERTIFICATE_PATH_HERE" />
<add key="OAuth2JwtCertificatePassword" value="INSERT_OAUTH2_JWT_CERTIFICATE_PASSWORD_HERE" />

No additional code is required to configure AdsUser in this case.

Dealing with invalid OAuth2 tokens

OAuth2 access tokens have a relatively short expiry time (about an hour). An OAuth2 access token may also become invalid if the user revokes the refresh token. There are two ways of handling an invalid OAuth2 access token.

1. Allow the AdWords API .NET library to automatically refresh the OAuth2 tokens.

Ads API client library can proactively refresh OAuth2 accessToken by keeping track of the time left for expiry of the token. It does so by looking at the UpdatedOn and ExpiresIn fields of the user's OAuthProvider instance. If you create new instances of AdsUser class every time you make an API call, then make sure you set these properties for the OAuthProvider instance of the new AdsUser class. If these fields are not provided, AdsUser will initialize these fields with system defaults, then attempt to obtain a new accessToken if refreshToken is provided. While this works for simple scripts, applications that spawn lots of threads may run into rate limiting issues as multiple AdsUser instances attempt to refresh access tokens simultaneously.

If you add the following key to your App.config, Ads API .NET library will also try to detect an invalid OAuth2 access token error (if the API also supports it) and refresh it. If it succeeds, it will retry the failed call; if it can’t, it will raise a System.ApplicationException with the original exception details.

<add key="RetryCount" value="1" />

If you need to save the access token after it is refreshed, then you can do so as follows:

oAuth2.OnOAuthTokensObtained += delegate(AdsOAuthProvider provider) {
  // Save your new OAuth2 tokens here.
};

2. Refresh the tokens yourself

If you wish to refresh the OAuth2 access tokens yourself, you can do so by calling user.OAuthProvider.RefreshAccessToken()

Referring to code examples

The code examples for using OAuth are available in the examples folder for each supported API.