I sorted this out. There were a few things I had to do differently:
Download the private key from Google as a p12 file. Convert the .p12 file I downloaded from Google into a pem file with the following command. The default password is 'notasecret'.
openssl pkcs12 -in key.p12 -nodes -nocerts > privatekey.pem
Force authentication to occur by using the Google apiclient library. The final code is below. client_email is the email address provided for the service user in the GAE console.
import httplib2
from oauth2client.client import SignedJwtAssertionCredentials
from apiclient.discovery import build
import gdata.spreadsheets
import gdata.spreadsheets.client
import gdata.gauth
import os
path = os.path.join(os.path.split(__file__)[0],'privatekey.pem')
with open(path) as keyfile:
private_key = keyfile.read()
credentials = SignedJwtAssertionCredentials(
'<client email>',
private_key,
scope=(
'https://www.googleapis.com/auth/drive',
'https://spreadsheets.google.com/feeds',
'https://docs.google.com/feeds',
))
http_auth = credentials.authorize(httplib2.Http())
authclient = build('oauth2','v2',http=http_auth)
auth2token = gdata.gauth.OAuth2TokenFromCredentials(credentials)
gd_client = gdata.spreadsheets.client.SpreadsheetsClient()
gd_client = auth2token.authorize(gd_client)
# Open the main roster feed
roster_sheet_key = '<key from spreadsheet url>'
feed = gd_client.GetWorksheets(roster_sheet_key)
I unfortunately couldn't figure out how to use the SpreadsheetService API that I had been using previously, but SpreadsheetsClient works well enough. I don't notice any significant performance difference between the two for what I'm doing with it.