Update (2015-06-15): The sunset date listed below has been changed from June 26th to July 6th, 2015.
Posted by Eric Koleda, Developer Platform Engineer
OAuth is the de facto standard for authorization today and is used by most modern APIs. Apps Script handles the OAuth flow automatically for dozens of built-in and advanced services, but until recently only had limited support for connecting to other OAuth-protected APIs such as Twitter, etc. The URL Fetch service’s OAuthConfig class only works with the older OAuth 1.0 standard and only allows the developer of the script (not its users) to grant access to their data. To address this, we’ve create two new open source libraries:
OAuthConfig
With only a few clicks, you can add these libraries to your scripts. The full source code is available on GitHub if you need to tinker with how they work. These libraries allow for greater control over the OAuth flow, including the ability for users to grant access separately, a long standing feature request from the community.
We believe that these open libraries are a better alternative to our previous solution, and therefore we are deprecating the OAuthConfig class. The class will continue to function until July 6, 2015, after which it will be removed completely and any scripts that use it will stop working We’ve prepared a migration guide that walks you through the process of upgrading your existing scripts to use these new libraries.
Separate from these changes in Apps Script and as announced in 2012, all Google APIs will stop supporting OAuth 1.0 for inbound requests on April 20, 2015. If you use OAuthConfig to connect to Google APIs, you will need to migrate before that date. Update your code to use the OAuth2 library or the API’s equivalent Advanced Service if one exists.
We see Apps Script and Sheets as the perfect hub for connecting together data inside and outside of Google, and hope this additional OAuth functionality makes it an even more compelling platform.
Editor's note: This post by Google Senior Product Manager Justin Smith has been cross-posted from the Google Code blog because we think it'll be of great interest to Google Apps developers. -- Ryan Boyd
In the coming weeks we will be making three changes to the experimental OAuth 2.0 endpoint. We expect the impact to be minimal, and we’re emailing developers who are most likely to be affected.
https://www.example.com/back?error=access_denied.
https://www.example.com/back?error=access_denied
https://www.example.com/back#error=access_denied
approval_prompt=force
access_type=offline
https://accounts.google.com/o/oauth2/auth? client_id=21302922996.apps.googleusercontent.com& redirect_uri=https://www.example.com/back& scope=https://www.google.com/m8/feeds/& response_type=code
https://accounts.google.com/o/oauth2/auth? client_id=21302922996.apps.googleusercontent.com& redirect_uri=https://www.example.com/back& scope=https://www.google.com/m8/feeds/& response_type=code& access_type=offline& approval_prompt=force
Since March of this year, Google has supported OAuth 2.0 for many APIs, including Google Data APIs such as Google Calendar, Google Contacts and Google Documents List. Google's implementation of OAuth 2.0 introduces many advantages compared to OAuth 1.0 such as simplicity for developers and a more polished user experience.
We’ve just added support for this authorization mechanism to the gdata-python-client library-- let’s take a look at how it works by retrieving an access token for the Google Calendar and Google Documents List APIs and listing protected data.
First, you will need to retrieve or sync the project from the repository using Mercurial:
hg clone https://code.google.com/p/gdata-python-client/
For more information about installing this library, please refer to the Getting Started With the Google Data Python Library article.
Now that the client library is installed, you can go to your APIs Console to either create a new project, or use information about an existing one from the API Access pane:
Your application will require the user to grant permission for it to access protected APIs on their behalf. It must redirect the user over to Google's authorization server and specify the scopes of the APIs it is requesting permission to access.
Available Google Data API’s scopes are listed in the Google Data FAQ.
Here's how your application can generate the appropriate URL and redirect the user:
import gdata.gauth # The client id and secret can be found on your API Console. CLIENT_ID = '' CLIENT_SECRET = '' # Authorization can be requested for multiple APIs at once by specifying multiple scopes separated by # spaces. SCOPES = ['https://docs.google.com/feeds/', 'https://www.google.com/calendar/feeds/'] USER_AGENT = '' # Save the token for later use. token = gdata.gauth.OAuth2Token( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, scope=' '.join(SCOPES), user_agent=USER_AGENT) # The “redirect_url” parameter needs to match the one you entered in the API Console and points # to your callback handler. self.redirect( token.generate_authorize_url(redirect_url='http://www.example.com/oauth2callback'))
If all the parameters match what has been provided by the API Console, the user will be shown this dialog:
When an action is taken (e.g allowing or declining the access), Google’s authorization server will redirect the user to the specified redirect URL and include an authorization code as a query parameter. Your application then needs to make a call to Google’s token endpoint to exchange this authorization code for an access token.
import atom.http_core url = atom.http_core.Uri.parse_uri(self.request.uri) if 'error' in url.query: # The user declined the authorization request. # Application should handle this error appropriately. pass else: # This is the token instantiated in the first section. token.get_access_token(url.query)
The redirect handler retrieves the authorization code that has been returned by Google’s authorization server and exchanges it for a short-lived access token and a long-lived refresh token that can be used to retrieve a new access token. Both access and refresh tokens are to be kept private to the application server and should never be revealed to other client applications or stored as a cookie.
To store the token object in a secured datastore or keystore, the gdata.gauth.token_to_blob() function can be used to serialize the token into a string. The gdata.gauth.token_from_blob() function does the opposite operation and instantiate a new token object from a string.
gdata.gauth.token_to_blob()
gdata.gauth.token_from_blob()
Now that an access token has been retrieved, it can be used to authorize calls to the protected APIs specified in the scope parameter.
import gdata.calendar.client import gdata.docs.client # Access the Google Calendar API. calendar_client = gdata.calendar.client.CalendarClient(source=USER_AGENT) # This is the token instantiated in the first section. calendar_client = token.authorize(calendar_client) calendars_feed = client.GetCalendarsFeed() for entry in calendars_feed.entry: print entry.title.text # Access the Google Documents List API. docs_client = gdata.docs.client.DocsClient(source=USER_AGENT) # This is the token instantiated in the first section. docs_client = token.authorize(docs_client) docs_feed = client.GetDocumentListFeed() for entry in docs_feed.entry: print entry.title.text
For more information about OAuth 2.0, please have a look at the developer’s guide and let us know if you have any questions by posting them in the support forums for the APIs you’re accessing.
Updated 9/30/2011 to fix a small typo in the code
Gmail servers support the standard IMAP and POP protocols for email retrieval but sometimes you only need to know whether there are any new messages in your inbox. Using any of the two protocols mentioned above may seem like an overkill in this scenario and that’s why Gmail also exposes a read only feed called Gmail Inbox Feed which you can subscribe to and get the list of unread messages in your inbox.
The Gmail Inbox Feed is easily accessible by pointing your browser to https://mail.google.com/mail/feed/atom and authenticating with your username and password if you are not already logged in.
Using basic authentication to access the inbox feed doesn’t provide a very good user experience if we want delegated access. In that case, we should instead rely on the OAuth authorization standard, which is fully supported by the Gmail Inbox Feed.
OAuth supports two different flows. With 3-legged OAuth, an user can give access to a resource he owns to a third-party application without sharing his credentials. The 2-legged flow, instead, resembles a client-server scenario where the application is granted domain-wide access to a resource.
Let’s write a .NET application that uses 2-legged OAuth to access the Gmail Inbox Feed for a user in the domain and list unread emails. This authorization mechanism also suits Google Apps Marketplace developers who want to add inbox notifications to their applications.
There is no dedicated client library for this task and the Inbox Feed is not based on the Google Data API protocol but we’ll still use the .NET library for Google Data APIs for its OAuth implementation.
First, create a new C# project and add a reference to the Google.GData.Client.dll released with the client library. Then add the following using directives to your code:
using System; using System.Linq; using System.Net; using System.Net.Mail; using System.Xml; using System.Xml.Linq; using Google.GData.Client;
The next step is to use 2-legged OAuth to send an authorized GET request to the feed URL. In order to do this, we need our domain’s consumer key and secret and the username of the user account we want to access the inbox feed for.
string CONSUMER_KEY = "mydomain.com"; string CONSUMER_SECRET = "my_consumer_secret"; string TARGET_USER = "test_user"; OAuth2LeggedAuthenticator auth = new OAuth2LeggedAuthenticator("GmailFeedReader", CONSUMER_KEY, CONSUMER_SECRET, TARGET_USER, CONSUMER_KEY); HttpWebRequest request = auth.CreateHttpWebRequest("GET", new Uri("https://mail.google.com/mail/feed/atom/")); HttpWebResponse response = request.GetResponse() as HttpWebResponse;
The response is going to be a standard Atom 0.3 feed, i.e. an xml document that we can load into an XDocument using the standard XmlReader class:
XDocument
XmlReader
XmlReader reader = XmlReader.Create(response.GetResponseStream()); XDocument xdoc = XDocument.Load(reader); XNamespace xmlns = "http://purl.org/atom/ns#";
All the parsing can be done with a single LINQ to XML instruction, which iterates the entries and instantiates a new MailMessage object for each email, setting its Subject, Body and From properties with the corresponding values in the feed:
MailMessage
Subject
Body
From
var messages = from entry in xdoc.Descendants(xmlns + "entry") from author in entry.Descendants(xmlns + "author") select new MailMessage() { Subject = entry.Element(xmlns + "title").Value, Body = entry.Element(xmlns + "summary").Value, From = new MailAddress( author.Element(xmlns + "email").Value, author.Element(xmlns + "name").Value) };
At this point, messages will contain a collection of MailMessage instances that we can process or simply dump to the console as in the following snippet:
Console.WriteLine("Number of messages: " + messages.Count()); foreach (MailMessage entry in messages) { Console.WriteLine(); Console.WriteLine("Subject: " + entry.Subject); Console.WriteLine("Summary: " + entry.Body); Console.WriteLine("Author: " + entry.From); }
If you have any questions about how to use the Google Data APIs .NET Client Library to access the Gmail Inbox Feed, please post them in the client library discussion group.
We have released version 1.9 of the .NET Library for Google Data APIs and it is available for download.
This version adds the following new features:
This new version also removes the client library for the deprecated Google Base API and fixes 20 bugs.
For more details, please check the Release Notes and remember to file feature requests or bugs in the project issue tracker.
AccountManager
GoogleAccountManager
GoogleAccountManager googleAccountManager = new GoogleAccountManager( activity); Account[] accounts = accountManager.getAccounts();
AccountManager.getAuthToken()
AccountManagerCallback
googleAccountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE, null, activity, new AccountManagerCallback<Bundle>() { public void run(AccountManagerFuture<Bundle> future) { try { // If the user has authorized your application to use the tasks API // a token is available. String token = future.getResult().getString( AccountManager.KEY_AUTHTOKEN); // Now you can use the Tasks API... useTasksAPI(token); } catch (OperationCanceledException e) { // TODO: The user has denied you access to the API, you // should handle that } catch (Exception e) { handleException(e); } } }, null);
AUTH_TOKEN_TYPE
String AUTH_TOKEN_TYPE = ”Manage your tasks”;
useTasksAPI(String accessToken) { // Setting up the Tasks API Service HttpTransport transport = AndroidHttp.newCompatibleTransport(); AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(accessToken); Tasks service = new Tasks(transport, accessProtectedResource, new JacksonFactory()); service.setKey(INSERT_YOUR_API_KEY); service.setApplicationName("Google-TasksSample/1.0"); // TODO: now use the service to query the Tasks API }
service
https://www.googleapis.com/tasks/v1/users/username/lists?key=<API_KEY>
Tasks
// Initializing the Tasks API serviceTasks service = new Tasks("2-LO Tasks Test", httpTransport, jsonFactory);service.accessKey = API_KEY;
Posted by Ankur Jain, Software Engineer
Want to weigh in on this topic? Discuss on Buzz
By Jeff Morgan, Senior Technical Consultant at Appirio
01 LOGIN username@googlemail.com P4$$w0rd
01 AUTHENTICATE XOAUTH R0VUIGh0dHBzOi8vbWFpbC5nb29nbGUuY29tL21haWwvYi91c2VybmFtZUBnb29nbGVtYWlsLmNvbS9pbWFwLyBvYXV0aF9jb25zdW1lcl9rZXk9ImFub255bW91cyIsb2F1dGhfbm9uY2U9IjEzMDQwNzM0Nzc4MTA1MDA2NTQzIixvYXV0aF9zaWduYXR1cmU9ImNhdWdodHlvdXBlZWtpbmciLG9hdXRoX3NpZ25hdHVyZV9tZXRob2Q9IkhNQUMtU0hBMSIsb2F1dGhfdGltZXN0YW1wPSIxMjY5Mzc3NzU5IixvYXV0aF90b2tlbj0ibm90cmVhbGx5IixvYXV0aF92ZXJzaW9uPSIxLjAiCg==