OAuth in the Google Data Protocol Client Libraries

Warning: This page is about Google's older APIs, the Google Data APIs; it's relevant only to the APIs that are listed in the Google Data APIs directory, many of which have been replaced with newer APIs. For information about a specific new API, see the new API's documentation. For information about authorizing requests with a newer API, see Google Accounts Authentication and Authorization.

This document describes how to use the Google Data API client libraries to connect to Google's OAuth Authentication for Web Applications.

The OAuth interface allows a web-based application to access a Google service on behalf of a user. To maintain a high level of security, OAuth enables the application to get an access token without ever handling the user's account login information.

The Google Data API client libraries provide methods to help you use OAuth in your web application. Specifically, there are methods for constructing the acquiring a request token, authorizing the request token, and exchanging the authorized request token for an access token. The libraries also handle the necessary signing algorithms when making requests to a Google Data service.

Audience

This document is intended for programmers who want their web-based applications to access Google services on behalf of users, using the Google Data APIs client libraries.

This document assumes that you are familiar with the OAuth interface and the general process for incorporating OAuth into your web application. For a complete description of OAuth's protocol, see OAuth Authentication for Web Applications or the official specification at oauth.net.

Using 3-legged OAuth and Google Data APIs without the client libraries

If you want your web application to interact with a Google Data service using OAuth as an authorization method, then everything you need to know is in OAuth Authentication for Web Applications. There's no need to use the Google Data APIs client libraries if you don't want to.

Here's an outline of how your application might authenticate a user using OAuth:

  1. Your application makes a signed request to fetch an initial OAuth request token from the OAuthRequestToken endpoint.
  2. Your application redirects the user to the appropriate OAuthAuthorizeToken URL to authorize the request token.
  3. Upon granting access, the user is redirected back to your application (the oauth_callback url)
  4. Your application sends a signed request to upgrade the authorized request token to an access token using the OAuthGetAccessToken endpoint.

The Google Data APIs client libraries simplify this authorization process by handling various details for you. This document explains how.

Registering your web application

OAuth requires that all API calls be digitally signed. Google supports the HMAC-SHA1 and RSA-SHA1 signature methods. In order to sign requests, your application first needs to register with Google. Once you've registered, Google will provide you with a consumer key (and secret for use with HMAC-SHA1), and a place to upload a public certificate.

1. Registering your domain

Please follow the steps outlined in Registration for Web-Based Applications.

2. Creating a private key / public certificate pair (optional)

If you choose to use RSA-SHA1 as the oauth_signature_method, you'll need to create a self-signing RSA private key and public certificate pair. See Generating a self-signing private key and public certificate (below) for examples on how to do that.

Working with 3-legged OAuth and the Google Data APIs: client library examples

The following sections show examples of using the Google Data APIs client library methods to follow the steps outlined in the "Working With OAuth" section of the OAuth documentation. All examples in this document assume that your application host domain is example.com.

Determining the scope of your data access

Each Google service defines a scope value that determines a token's access to the user's data. The available scope values are listed in the Google Data FAQ. For example, to use the Documents List API, set the scope to https://docs.google.com/feeds/, as listed in the FAQ.

Note: Set the scope value to the narrowest URL that permits the access you need. This lessens the chance of accidentally obtaining and leaking personal data. For example, if you want to access the current user's private Document List feed, use the scope https://docs.google.com/feeds/default/private/full instead of a broader scope like https://docs.google.com/feeds/, which provides access to all Document List feeds.

Multi-scoped tokens

To create tokens that access multiple Google Data APIs, separate each scope with a space character. The example below creates a token with access to both a user's Google Documents and Google Calendar data.

scope=https://www.google.com/calendar/feeds/ https://docs.google.com/feeds/
URL-encoding

Non-ASCII characters that appear in URLs, including colon, slash, and space, must be URL-encoded in order to be transmitted via HTTP. Google Data API client libraries automatically URL-encode parameters for you, so you can simply use non-URL-encoded strings when assigning values to parameters. For example, you can make the following assignment in your code:

scope=https://www.google.com/calendar/feeds/ https://docs.google.com/feeds/

When you call the client library, the scope parameter is then automatically URL-encoded to the following value:
https%3a%2f%2fwww.google.com%2fcalendar%2ffeeds%2f+https%3a%2f%2fdocs.google.com%2ffeeds%2f

Fetching a request token

Java

For HMAC-SHA1, you need some way to persist the token secret (obtained in the response) in order to create an OAuth token object coming back from the approval page. To do that, set a session variable or cookie.

import com.google.gdata.client.docs.*;
import com.google.gdata.client.authn.oauth.*;

String CONSUMER_KEY = "example.com";
String CONSUMER_SECRET = "abc123doremi";

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
oauthParameters.setScope("https://docs.google.com/feeds/");
oauthParameters.setOAuthCallback("http://www.example.com/UpgradeToken.jsp");

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
oauthHelper.getUnauthorizedRequestToken(oauthParameters);

Using RSA-SHA1, the oauth_token_secret is unused so there's no need to persist the token secret.

import com.google.gdata.client.docs.*;
import com.google.gdata.client.authn.oauth.*;

String CONSUMER_KEY = "example.com";

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setScope("https://docs.google.com/feeds/");
oauthParameters.setOAuthCallback("http://www.example.com/UpgradeToken.jsp");

PrivateKey privKey = getPrivateKey("/path/to/your/rsakey.pk8");

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
oauthHelper.getUnauthorizedRequestToken(oauthParameters);

...

public static PrivateKey getPrivateKey(String privKeyFileName) {
  File privKeyFile = new File(privKeyFileName);
  FileInputStream fis = new FileInputStream(privKeyFile);
  DataInputStream dis  = new DataInputStream(fis);

  byte[] privKeyBytes = new byte[(int) privKeyFile.length()];
  dis.read(privKeyBytes);
  dis.close();
  fis.close();

  String BEGIN = "-----BEGIN PRIVATE KEY-----";
  String END = "-----END PRIVATE KEY-----";
  String str = new String(privKeyBytes);
  if (str.contains(BEGIN) && str.contains(END)) {
    str = str.substring(BEGIN.length(), str.lastIndexOf(END));
  }

  KeyFactory fac = KeyFactory.getInstance("RSA");
  EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(Base64.decode(str));
  return fac.generatePrivate(privKeySpec);
}

PHP

Using HMAC-SHA1 as the signature method:

require_once 'Zend/Oauth/Consumer.php';

session_start();

$CONSUMER_KEY = 'example.com';
$CONSUMER_SECRET = 'abc123doremi';

// Multi-scoped token.
$SCOPES = array(
  'https://docs.google.com/feeds/',
  'https://spreadsheets.google.com/feeds/'
);

$oauthOptions = array(
  'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
  'version' => '1.0',
  'consumerKey' => $CONSUMER_KEY,
  'consumerSecret' => $CONSUMER_SECRET,
  'signatureMethod' => 'HMAC-SHA1',
  'callbackUrl' => 'http://myapp.example.com/access_token.php',
  'requestTokenUrl' => 'https://www.google.com/accounts/OAuthGetRequestToken',
  'userAuthorizationUrl' => 'https://www.google.com/accounts/OAuthAuthorizeToken',
  'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken'
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);

// When using HMAC-SHA1, you need to persist the request token in some way.
// This is because you'll need the request token's token secret when upgrading
// to an access token later on. The example below saves the token object as a session variable.
if (!isset($_SESSION['ACCESS_TOKEN'])) {
  $_SESSION['REQUEST_TOKEN'] = serialize($consumer->getRequestToken(array('scope' => implode(' ', $SCOPES))));
}

Using RSA-SHA1 as the signature method:

require_once 'Zend/Crypt/Rsa/Key/Private.php';
require_once 'Zend/Oauth/Consumer.php';

session_start();

$CONSUMER_KEY = 'example.com';
$SCOPE = 'https://docs.google.com/feeds/';

$oauthOptions = array(
  'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
  'version' => '1.0',
  'consumerKey' => $CONSUMER_KEY,
  'consumerSecret' => new Zend_Crypt_Rsa_Key_Private(file_get_contents(realpath('/path/to/yourRSAPrivateKey.pem'))),
  'signatureMethod' => 'RSA-SHA1',
  'callbackUrl' => 'http://myapp.example.com/access_token.php',
  'requestTokenUrl' => 'https://www.google.com/accounts/OAuthGetRequestToken',
  'userAuthorizationUrl' => 'https://www.google.com/accounts/OAuthAuthorizeToken',
  'accessTokenUrl' => 'https://www.google.com/accounts/OAuthGetAccessToken'
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);

if (!isset($_SESSION['ACCESS_TOKEN'])) {
  $_SESSION['REQUEST_TOKEN'] = serialize($consumer->getRequestToken(array('scope' => $SCOPE)));
}

Python

Using HMAC-SHA1 as the signature method:

If you're using the newer v2.0+ classes based on GDClient, use:

import gdata.gauth
import gdata.docs.client

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'
SCOPES = ['https://docs.google.com/feeds/', 'https://www.google.com/calendar/feeds/']  # example of a multi-scoped token

client = gdata.docs.client.DocsClient(source='yourCompany-YourAppName-v1')

oauth_callback_url = 'http://%s/get_access_token' % self.request.host
request_token = client.GetOAuthToken(
    SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)

# When using HMAC-SHA1, you need to persist the request_token in some way.
# You'll need the token secret when upgrading to an access token later on.
# In Google App Engine, you can use the AeSave helper:
# gdata.gauth.AeSave(request_token, 'myKey')

Using RSA-SHA1 as the signature method:

...

f = open('/path/to/yourRSAPrivateKey.pem')
RSA_KEY = f.read()
f.close()

request_token = client.GetOAuthToken(SCOPES, oauth_callback_url, CONSUMER_KEY, rsa_private_key=RSA_KEY)

Alternatively, if you're using the older v1.0 classes based on GDataService, the calls are a bit different:

import gdata.auth
import gdata.docs.service

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.HMAC_SHA1, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)

req_token = client.FetchOAuthRequestToken()
client.SetOAuthToken(req_token)

Using RSA-SHA1 as the signature method:

...

f = open('/path/to/yourRSAPrivateKey.pem')
RSA_KEY = f.read()
f.close()

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(gdata.auth.OAuthSignatureMethod.RSA_SHA1, CONSUMER_KEY, rsa_key=RSA_KEY)

SCOPES = ['https://docs.google.com/feeds/', 'https://www.google.com/calendar/feeds/']  # example of a multi-scoped token
req_token = client.FetchOAuthRequestToken(scopes=SCOPES)
client.SetOAuthToken(req_token)

.NET

Using HMAC-SHA1 as the signature method:

using Google.GData.Client;

string CONSUMER_KEY = "example.com";
string CONSUMER_SECRET = "abc123doremi";

// Multi-scoped token.
string SCOPE = "https://www.google.com/calendar/feeds/ https://www.google.com/m8/feeds/";

OAuthParameters parameters = new OAuthParameters() {
  ConsumerKey = CONSUMER_KEY,
  ConsumerSecret = CONSUMER_SECRET,
  Scope = SCOPE,
  Callback = "http://myapp.example.com/access_token",
  SignatureMethod = "HMAC-SHA1"
}

OAuthUtil.GetUnauthorizedRequestToken(parameters);

Using RSA-SHA1 as the signature method:

RSA-SHA1 is not supported yet.

Authorizing a request token

To authorize a request token, your application must redirect the user to the OAuthAuthorizeToken URL, which prompts them to log into their Google account. For more information on the OAuthAuthorizeToken URL, see the full OAuth Authentication for Web Applications.

To construct the OAuthAuthorizeToken URL in your application, use the following for each client library. Note, these samples build on the previous examples.

After constructing the approval page URL, your application can use it in a variety of ways to send the user to the OAuthAuthorizeToken handler. The most common approach is to redirect the user or display a link to that page.

Java

For HMAC-SHA1:

String approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
System.out.println(approvalPageUrl);

For RSA-SHA1:

String approvalPageUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
System.out.println(approvalPageUrl);

PHP

// If on a G Suite domain, use your domain for the hd param (e.g. 'example.com').
$approvalUrl = $consumer->getRedirectUrl(array('hd' => 'default'));
echo "<a href=\"$approvalUrl\">Grant access</a>";

Alternatively, you can simply redirect to the approval URL:

// If on a G Suite domain, use your domain for the hd param (e.g. 'example.com').
$consumer->redirect(array('hd' => 'default'));

Python

If you're using the newer v2.0+ classes based on GDClient, use:

# req_token is from previous call to client.GetOAuthToken()
domain = None  # If on a G Suite domain, use your domain (e.g. 'example.com').
self.redirect(request_token.generate_authorization_url(google_apps_domain=domain))

If you're using the older v1.0 classes based on GDataService, the process is a bit different.

# req_token is from previous call to client.FetchOAuthRequestToken()
oauth_callback_url = 'http://%s/get_access_token' % self.request.host
self.redirect(client.GenerateOAuthAuthorizationURL(callback_url=oauth_callback_url))

.NET

string authorizationUrl = OAuthUtil.CreateUserAuthorizationUrl(parameters);
Console.WriteLine(authorizationUrl);

Extracting the token from the callback URL

When Google redirects back to your application, the oauth_token is appended to the "oauth_callback_url" URL as a query parameter. Your application should then extract the token value from its URL query parameter and re-establish the oauth parameters.

The client libraries provide convenience methods for extracting the oauth_token. These samples build on the previous examples.

Java

If you've chosen to persist the token secret in the callback URL (when using HMAC-SHA1):

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthHmacSha1Signer());
oauthHelper.getOAuthParametersFromCallback(request.getQueryString(), oauthParameters);

The only difference with RSA-SHA1 is the signing method:

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);

PrivateKey privKey = getPrivateKey("/path/to/your/rsakey.pk8");

GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(new OAuthRsaSha1Signer(privKey));
oauthHelper.getOAuthParametersFromCallback(request.getQueryString(), oauthParameters);

PHP

This step isn't necessary when using the PHP library.

Python

If you're using the newer v2.0+ classes based on GDClient, use:

# Recall request_token. In Google App Engine, use AeLoad():
# saved_request_token = gdata.gauth.AeLoad('myKey')

request_token = gdata.gauth.AuthorizeRequestToken(saved_request_token, self.request.uri)

If you're using the older v1.0 classes based on GDataService, use:

oauth_token = gdata.auth.OAuthTokenFromUrl(self.request.uri)
if oauth_token:
  oauth_token.secret = # TODO: recall saved request_token and set the token secret here.
  oauth_token.oauth_input_params = gdata.auth.OAuthInputParams(
      gdata.auth.OAuthSignatureMethod.HMAC_SHA1, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
 client.SetOAuthToken(oauth_token)
else:
  print 'No oauth_token found in the URL'

The process is similar for RSA-SHA1, but without the token secret:

oauth_token = gdata.auth.OAuthTokenFromUrl(self.request.uri)
if oauth_token:
  oauth_token.oauth_input_params = gdata.auth.OAuthInputParams(
      gdata.auth.OAuthSignatureMethod.RSA_SHA1, CONSUMER_KEY, rsa_key=RSA_KEY)
 client.SetOAuthToken(oauth_token)
else:
  print 'No oauth_token found in the URL'

.NET

If you've chosen to persist the token secret in the callback URL:

OAuthUtil.UpdateOAuthParametersFromCallback(url, parameters);

Upgrading to an access token

The last step in the OAuth token dance is to upgrade the authorized request token to a long-lived access token using the OAuthGetAccessToken URL, as described in the full OAuth Authentication for Web Applications documentation.

Here are some examples using each of the client libraries:

Java

String accessToken = oauthHelper.getAccessToken(oauthParameters);
// You can also pull the OAuth token string from the oauthParameters:
// String accessToken = oauthParameters.getOAuthToken();
System.out.println("OAuth Access Token: " + accessToken);

String accessTokenSecret = oauthParameters.getOAuthTokenSecret();
System.out.println("OAuth Access Token's Secret: " + accessTokenSecret);

PHP

if (!isset($_SESSION['ACCESS_TOKEN'])) {
  if (!empty($_GET) && isset($_SESSION['REQUEST_TOKEN'])) {
    $_SESSION['ACCESS_TOKEN'] = serialize($consumer->getAccessToken($_GET, unserialize($_SESSION['REQUEST_TOKEN'])));
  }
}

Python

If you're using the newer v2.0+ classes based on GDClient, use:

# Upgrade the token and save in the user's datastore
access_token = client.GetAccessToken(request_token)

# If you're using Google App Engine, you can call the AeSave() method to save
# the access token under the current logged in user's account.
#gdata.gauth.AeSave(access_token, token_key)

If you're using the older v1.0 classes based on GDataService, use:

access_token = client.UpgradeToOAuthAccessToken()  # calls SetOAuthToken() for you

If you're using gdata.gauth.AeSave() on App Engine, the token and token secret will be stored for you under the current logged in user.

.NET

OAuthUtil.GetAccessToken(parameters);

// If you want to extract the OAuth Token/TokenSecret from the OAuthParameters instance:
string accessToken = parameter.Token;
Console.WriteLine("OAuth Access Token: " + accessToken);

string accessTokenSecret = parameter.TokenSecret;
Console.WriteLine("OAuth Access Token's Secret: " + accessTokenSecret);

Note: If you're using HMAC-SHA1, be sure to save the access token's token secret alongside the token value in your database, otherwise you won't be able to properly reconstruct the oauth parameters for later use.

Using an access token

After you've obtained an access token, use the standard Google Data APIs client library calls to interact with the service. The library will take care of signing the requests and including the correct Authorization header for you. Typically, you'll be recalling the user's token from a cookie or database. These examples demonstrate how to reconstruct the oauth parameters and make a client library call.

Java

If you're using HMAC-SHA1:

  GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
  oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
  oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
  oauthParameters.setOAuthToken(ACCESS_TOKEN);
  oauthParameters.setOAuthTokenSecret(TOKEN_SECRET);

  DocsService client = new DocsService("yourCompany-YourAppName-v1");
  client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());

  URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
  DocumentListFeed resultFeed = client.getFeed(feedUrl, DocumentListFeed.class);
  for (DocumentListEntry entry : resultFeed.getEntries()) {
    System.out.println(entry.getTitle().getPlainText());
  }
  

The difference with RSA-SHA1 is that you don't need to set the access token's secret and constructing the signer object is different:

  GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
  oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
  oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
  oauthParameters.setOAuthToken(ACCESS_TOKEN);

  PrivateKey privKey = getPrivateKey("/path/to/your/rsakey.pk8");  // See above for the defintion of getPrivateKey()

  DocsService client = new DocsService("yourCompany-YourAppName-v1");
  client.setOAuthCredentials(oauthParameters, new OAuthRsaSha1Signer(privKey));

  URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full");
  DocumentListFeed resultFeed = client.getFeed(feedUrl, DocumentListFeed.class);
  for (DocumentListEntry entry : resultFeed.getEntries()) {
    System.out.println(entry.getTitle().getPlainText());
  }
  

PHP

require_once 'Zend/Gdata/Docs.php';

if (isset($_SESSION['ACCESS_TOKEN'])) {
  $accessToken = unserialize($_SESSION['ACCESS_TOKEN']);
} else {
  exit;
}


/*  Or, you could set an existing token (say one stored from your database). For HMAC-SHA1:
$accessToken = new Zend_Oauth_Token_Access();
$accessToken->setToken('1/AQfoI-qJDqkvvkf216Gc2g');
$accessToken->setTokenSecret('2c26GLW250tZiQ');
*/

$httpClient = $accessToken->getHttpClient($oauthOptions);
$client = new Zend_Gdata_Docs($httpClient, "yourCompany-YourAppName-v1");

// Retrieve user's list of Google Docs
$feed = $client->getDocumentListFeed();
foreach ($feed->entries as $entry) {
  echo "$entry->title\n";
}

Python

This snippet assumes that you have already fetched an access token (using HMAC-SHA1) and are recalling that token key/secret for later use.

If you're using the newer v2.0+ classes based on GDClient, use:

client = gdata.docs.client.DocsClient(source='yourCo-yourAppName-v1')
client.auth_token = gdata.gauth.OAuthHmacToken(CONSUMER_KEY, CONSUMER_SECRET, TOKEN,
                                               TOKEN_SECRET, gdata.gauth.ACCESS_TOKEN)
feed = client.GetDocList()
for entry in feed.entry:
  print entry.title.text

If you're using the older v1.0 classes based on GDataService, use:

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(SIG_METHOD, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)

# the token key and secret should be recalled from your database
client.SetOAuthToken(gdata.auth.OAuthToken(key=TOKEN, secret=TOKEN_SECRET))

feed = client.GetDocumentListFeed()
for entry in feed.entry:
  print entry.title.text

.NET

If you're using HMAC-SHA1:

OAuthParameters parameters = new OAuthParameters() {
  ConsumerKey = CONSUMER_KEY,
  ConsumerSecret = CONSUMER_SECRET,
  Token = ACCESS_TOKEN,
  TokenSecret = TOKEN_SECRET
}

GOAuthRequestFactory requestFactory = new GOAuthRequestFactory("writely", APPLICATION_NAME, parameters);

DocsService service = new DocsService(APPLICATION_NAME);
service.RequestFactory = requestFactory;

DocumentsListQuery query = new DocumentsListQuery();
DocumentsFeed feed = service.Query(query);
foreach (DocumentEntry entry in feed.Entries) {
  Console.WriteLine(entry.Title.Text);
}

The difference with RSA-SHA1 is that you don't need to set the access token's secret and constructing the signer object is different:

RSA-SHA1 is not supported yet.

Additional 3-Legged OAuth Resources and Samples

Back to top

2 Legged OAuth

2 legged OAuth allows trusted applications to access users' Google Data without their direct involvement. Two key groups can use two-legged OAuth:

G Suite domain administrators: Administrators can build scripts and custom applications that manage the user data for their domain through Google Data APIs. To learn about managing the key and secret that's associated with your G Suite domain, and granting global access control, see "Managing the OAuth key and secret".

Third-party software vendors: Vendors may offer applications that use two-legged OAuth to integrate with G Suite. Access for the 3rd party applications can be granted on the Manage API client page or by installing from the G Suite Marketplace.

An access token is not required as per the normal authorization flow (also referred to as 3-legged OAuth).

The following client library samples demonstrate how to setup your client to use 2 Legged OAuth using HMAC-SHA1.

Java

import com.google.gdata.client.docs.*;
import com.google.gdata.client.authn.oauth.*;

String CONSUMER_KEY = "example.com";
String CONSUMER_SECRET = "abc123doremi";

GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);

DocsService client = new DocsService("yourCompany-YourAppName-v1");
client.setOAuthCredentials(oauthParameters, new OAuthHmacSha1Signer());

// Retrieve user's list of Google Docs
String user = "any.user@anydomain.com";
URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full" +
                      "?xoauth_requestor_id=" + user);

DocumentListFeed resultFeed = client.getFeed(feedUrl, DocumentListFeed.class);
for (DocumentListEntry entry : resultFeed.getEntries()) {
  System.out.println(entry.getTitle().getPlainText());
}

PHP

require_once 'Zend/Oauth/Consumer.php';
require_once 'Zend/Gdata/Docs.php';

$CONSUMER_KEY = 'example.com';
$CONSUMER_SECRET = 'abc123doremi';
$USER = 'any.user@anydomain.com';

$oauthOptions = array(
    'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
    'version' => '1.0',
    'signatureMethod' => 'HMAC-SHA1',
    'consumerKey' => $CONSUMER_KEY,
    'consumerSecret' => $CONSUMER_SECRET
);

$consumer = new Zend_Oauth_Consumer($oauthOptions);
$token = new Zend_Oauth_Token_Access();
$httpClient = $token->getHttpClient($oauthOptions);

$client = new Zend_Gdata_Docs($httpClient);

// Retrieve user's list of Google Docs
$feed = $client->getDocumentListFeed('https://docs.google.com/feeds/default/private/full?xoauth_requestor_id=' . urlencode($USER));
foreach ($feed->entries as $entry) {
  echo "$entry->title\n";
}

Python

If you're using the newer v2.0+ classes based on GDClient, use:

import gdata.gauth
import gdata.docs.client

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'
requestor_id = 'any.user@anydomain.com'

client = gdata.docs.client.DocsClient(source='yourCompany-YourAppName-v1')
client.auth_token = gdata.gauth.TwoLeggedOAuthHmacToken(
    CONSUMER_KEY, CONSUMER_SECRET, requestor_id)

# Retrieve user's list of Google Docs
feed = client.GetDocList()
for entry in feed.entry:
  print entry.title.text

If you're using the older v1.0 classes based on GDataService, use:

import gdata.auth
import gdata.docs.service

CONSUMER_KEY = 'example.com'
CONSUMER_SECRET = 'abc123doremi'
SIG_METHOD = gdata.auth.OAuthSignatureMethod.HMAC_SHA1

requestor_id = 'any.user@anydomain.com'

client = gdata.docs.service.DocsService(source='yourCompany-YourAppName-v1')
client.SetOAuthInputParameters(SIG_METHOD, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET,
                               two_legged_oauth=True, requestor_id=requestor_id)

# Retrieve user's list of Google Docs
feed = client.GetDocumentListFeed()
for entry in feed.entry:
  print entry.title.text

# Change to another user on your domain
client.GetOAuthInputParameters().requestor_id = 'another.user@example.com'

.NET

using Google.GData.Client;
using Google.GData.Documents;

// Create an OAuth factory to use
GOAuthRequestFactory requestFactory = new GOAuthRequestFactory("writely", "yourCompany-YourAppName-v1");
requestFactory.ConsumerKey = "example.com";
requestFactory.ConsumerSecret = "abc123doremi";

String user = "any.user@anydomain.com";

DocumentsService client = new DocumentsService("yourCompany-YourAppName-v1");
client.RequestFactory = requestFactory;

// Retrieve user's list of Google Docs
DocumentsListQuery query = new DocumentsListQuery();
query.Uri = new OAuthUri("https://docs.google.com/feeds/default/private/full", user, requestFactory.ConsumerKey);

DocumentsFeed feed = client.Query(query);

foreach (DocumentEntry entry in feed.Entries)
{
  Console.WriteLine(entry.Title.Text);
}

Additional 2-Legged OAuth Resources and Samples

Generating a self-signing private key and public certificate

The private key is used to generate a signature, which must be included with each request. The public key embedded in the certificate is used by Google to verify the signature. The public key must be a 1024-bit RSA key encoded in an X.509 certificate in PEM format. The certificate should be sent to Google at time of registration.

The following sections provide examples of how to generate keys and certificates using two particular tools: the OpenSSL utility and Java's keytool utility.

These examples are not specific to the Google Data APIs; you can use the same utilities to generate keys for any purpose.

The examples assume that your company is named My_Company, and is located in Mountain View, California, US, with domain name example.com.

Generating keys using OpenSSL

To create a pair of RSA keys and the corresponding certificate, you could use the following command:

# Generate the RSA keys and certificate
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  myrsakey.pem -out /tmp/myrsacert.pem

Warning: Including the -nodes parameter creates a private key without a password to protect it. However, you should consider omitting this parameter for added security.

The -sha1 parameter specifies that the key will be used to generate SHA1 signatures.

The -subj parameter specifies the identity of the application that the certificate represents.

The -keyout parameter specifies the file that will contain the keys. This file contains sensitive information and should be protected and not shared with anyone.

The -out parameter specifies the file that will contain the certificate in PEM format (which can be sent to Google while registering).

Generating keys for the .NET client

The .NET framework doesn't understand keys or certificates stored in the PEM format. Therefore, an additional step is needed once you have created the .pem file:

openssl pkcs12 -export -in test_cert.pem -inkey myrsacert.pem -out myrsacert.pfx -name "Testing Certificate"

This step generates a PFX file from your private key and certificate. This file can be imported into the .NET client library to digitally sign requests made to the Google Data APIs.

Generating keys for the Java client

The Java client accepts private keys in the PKCS#8 format. After generating a key/cert using the directions above, create a .pk8 file from your generated .pem file:

openssl pkcs8 -in myrsakey.pem -topk8 -nocrypt -out myrsakey.pk8

Alternatively, you can use the Java key store and the keytool utility to create a pair of RSA keys and the corresponding certificate. Use the following command:

# Generate the RSA keys and certificate
keytool -genkey -v -alias Example -keystore ./Example.jks\
  -keyalg RSA -sigalg SHA1withRSA\
  -dname "CN=www.example.com, OU=Engineering, O=My_Company, L=Mountain  View, ST=CA, C=US"\
  -storepass changeme -keypass changeme

Warning: "changeme" is not a good password; this is just an example.

The -dname parameter specifies the identity of the application that the certificate represents. The -storepass parameter specifies the password to protect the keystore. The -keypass parameter specifies the password to protect the private key.

To write the certificate to a file that can be used in the ManageDomains tool, use the following command:

# Output the public certificate to a file
keytool -export -rfc -keystore ./Example.jks -storepass changeme \
  -alias Example -file mycert.pem

Back to top