Domain-wide delegation of authority and OAuth 2.0 Service Accounts

Tuesday, November 6, 2012 | 11:20 AM

Labels:

Some enterprise applications need to programmatically access their users’ data without any manual authorization on their part. For example, you might want to use the Tasks API to add a task to all of your employees’ Google Tasks lists during the holiday season to remind them of something like, “Come pick up your holiday gift at the front desk!” Or, you might want to run some company-wide analysis of the content of your employees’ Google Drive.

In Google Apps domains, the domain administrator can grant applications domain-wide access to its users' data — this is referred as domain-wide delegation of authority. This basically allows applications to act on behalf of Google Apps domain users when using APIs.

Until recently this technique was mostly performed using 2-Legged OAuth 1.0a (2-LO). However, with the deprecation of the OAuth 1.0 protocol and the resulting programmed shutdown of 2-LO, the recommended authorization mechanism is now to use OAuth 2.0 and service accounts.

Unlike regular Google accounts that belong to an end user, service accounts are owned by your application and therefore identify your application. They can be created in the Google APIs Console and come with their own OAuth 2.0 credentials.

Google Apps domain administrators can delegate domain-wide authority to the service account’s credentials for a set of APIs. This results in allowing the application, by using the service account’s credentials, to act on behalf of the Google Apps domain’s users.

If you’d like to learn more, have a look at the recently published Google Drive SDK documentation on using OAuth 2.0 and service accounts for domain-wide delegation of authority.. These documents provide a step by step process and code samples to help you get started with service accounts.

Nicolas Garnier Google + | Twitter

Nicolas Garnier joined Google’s Developer Relations in 2008 and lives in Zurich. He is a Developer Advocate for Google Drive and Google Apps. Nicolas is also the lead engineer for the OAuth 2.0 Playground.

Instant voting with Apps Script

Thursday, November 1, 2012 | 10:10 AM

Labels:

From nations choosing presidents to offices selecting which coffee to brew, we often find ourselves involved in election systems designed to choose the best option. This spring my alma mater's solar vehicle team, CalSol, needed to elect new leaders. Our previous system was painfully slow, involved "raising hands" in a room, and excluded any team members who could not attend a specific meeting. I set out to solve these problems and the result was an easy method for running fair elections in a matter of minutes.

I was able to build the system completely on Google products and technologies:

  • Google Forms: Allows members to submit their votes from anywhere.
  • Google Spreadsheets: Makes it easy to audit the votes and configure the system.
  • Google Apps Script: Simple way to access the results and determine the winner.

I used a lesser known voting system called instant-runoff voting (IRV), or the alternative vote, which asks voters to rank candidates rather than cast a single vote. These votes, along with a secret voting key which I provided to each member, are recorded with a Google Form that automatically populates a spreadsheet. The code in Apps Script looks through the spreadsheet to count the votes while ensuring that each voting key is only used once. The secret keys not only prevent voters from casting multiple votes, but they also allow voters to change their vote by submitting the form again.

Below is a simplified snippet of code that shows the general process used to calculate the winner.

/* Some code omitted for clarity */

/* candidates is a list of names (strings) */
var candidates = get_all_candidates(results_range);

/* votes is an object mapping candidate names -> number of votes */
var votes = get_votes(results_range, candidates, keys_range, valid_keys);

/* winner is candidate name (string) or null */
var winner = get_winner(votes, candidates);

while (winner == null) {
  /* Modify candidates to only include remaining candidates */
  get_remaining_candidates(votes, candidates);
  if (candidates.length == 0) {
    Browser.msgBox("Tie");
    return;
  }
  votes = get_votes(results_range, candidates, keys_range, valid_keys);
  winner = get_winner(votes, candidates);
}
Browser.msgBox("Winner: " + winner);

I learned that putting a little effort into Apps Script can make people happy and save a lot of time. The team feedback was outstanding. One CalSol member said the process was an "Excellent, clean, and professional voting process. This should become a standard [for the team]." I was elated when I was able to close the polls during a meeting and announce the winners of twelve independent elections in just a matter of minutes.

If you like, you can watch a video demonstrating how to create and run your own election using this script:

Try the script yourself to make sure your coffee preferences are heard!


Chris Cartland profile | GitHub

Chris is a Developer Programs Engineer based in Mountain View on the Google+ team. He previously worked on solar vehicles at UC Berkeley and wants developers to write software that makes our lives better. In his spare time he likes to play soccer and throw the ball in after doing a front handspring.

Announcing Election Info: Using Apps Script to Provide Voting Information

Wednesday, October 31, 2012 | 1:09 PM

Labels:

It’s time for the 2012 General Election in the United States and along with it comes the tedious process of finding your voter registration, polling sites, times, directions, etc. The previously announced Google Civic Information API provides a great service to programmatically obtain much of this information based on the your home address. Google Apps Script makes it really quick and easy to build a web application that queries this information and uses various Google services to organize and track your information.

Election Info is a sample application built using Apps Script that can:

  • Query the Google Civic Information API to find polling locations and hours using client side JavaScript and AJAX.
  • Display polling information using HtmlService with jQuery for a clean effective UI.
  • Generate static maps via UrlFetch and the MapsService to show polling maps and directions.
  • Create a calendar event for election day with your polling location using the Calendar service.
  • Generate a bring-along document with poll directions and hours using the Document service.
  • Send you an email with a summary with your polling place information using the Gmail service.
  • Store your previous searches in UserProperties so it will remember your likely home address the next time you launch the app.

As you can see, this is a comprehensive sample app that is useful while also highlighting key Apps Script capabilities.

Install the app from the Chrome Web Store. Check back soon as we will be writing a blog post with details and sample code on how the sample was built.



Arun Nagarajan   profile | twitter

Arun is a Developer Advocate on Google Apps Script. Arun works closely with the community of partners, customers and developers to help them build compelling applications on top of Google Apps using Apps Script. In the past, he spent over 9 years building and designing platforms and infrastructure for enterprise mobile applications.. Arun is originally from the Boston area and enjoys basketball and snowboarding.

DrEdit for Google Drive and Learning AngularJS

Tuesday, October 30, 2012 | 9:47 AM

Labels:

Since we released version 2 of the Google Drive SDK at Google I/O, we’ve been quietly updating the DrEdit sample application to use the new API. As part of the update, the UI for DrEdit has been rewritten to use AngularJS, a modern web application toolset developed by Google and used in apps at DoubleClick. You might be wondering -- why go through the trouble of rewriting the UI for a basic sample app just to show off some new API features? Turns out it was more of a happy coincidence, but a valuable one and great learning experience!

Practice what you preach

I had the pleasure of co-presenting a session on building great apps for Google Drive, and a big focus of the talk was on all the little things that go into making an app intuitive and user-friendly. This is particularly important for Google Drive, where many users are already familiar with the built-in apps like Docs, Presentations, and Spreadsheets.

The first version of DrEdit was a good demo app, but didn’t follow all of our recommendations. I didn’t want to tell developers all the things they should be doing without having tried them myself. I decided to write a separate sample for the talk and needed a solid base to build on. It was the perfect opportunity to learn a new tool!

HTML & Javascript, only smarter

Angular doesn’t aim to abstract away HTML, Javascript & CSS. Rather, it enhances HTML to make building dynamic apps easier. One benefit, besides a nice short learning curve, is the positive interaction with other tools. To give the app some structure, I used Bootstrap. For example, the HTML for displaying the authenticated user’s info and a small dropdown to link to their profile in the navigation bar only required a few minor changes from typical Bootstrap usage (shown in bold) to wire up to a controller.

<ul class="nav pull-right" ng-controller="UserCtrl">
  <li class="dropdown">
    <a class="dropdown-toggle" data-toggle="dropdown" href="#">
    {{user.email}}
    </a>
    <ul class="dropdown-menu">
      <li><a href="{{user.link}}" target="_blank">Profile</a></li>
    </ul>
  </li>
</ul>

Even models are plain javascript objects. Anything reachable through a scope (the binding between a view and controller) is considered part of the model. These can be primitives, hashes, or objects. No need to extend a base class or access properties through special properties. Rather than use change listeners that require special instrumentation, Angular uses dirty checking to detect model changes and update views.

The one catch with this approach is it requires any changes to the model to be made inside the scope of a scope.$apply(fn) call. In most cases, this is done automatically. When working with external libraries or raw XMLHttpRequests that can fire asynchronous callbacks, calling $apply yourself is necessary to make sure mutations are tracked correctly.

Speaking of asynchronous tasks…

Promises, Promises

No, I’m not talking about the hit song by 80’s band Naked Eyes, rather Angular’s $q service based on one of the proposed CommonJS Promises APIs. If you’re already familiar with JQuery’s deferred object or any of the other related implementations, this is familiar territory. If not, time to learn. Working with deferred objects can be a lot easier than the traditional callback approach. You can compose async tasks either serially or in parallel, chain callbacks, and return deferred objects from functions like normal results.

Where this mostly comes into play is Angular’s $http service. If you’ve used jQuery, you’ll find it similar to jQuery.ajax() & the jqXHR result. It is based on the deferred/promises API and also ensures callbacks are executed correctly inside $apply for safe & efficient model mutations. This combination makes it easy to work with remote services in Angular.

Room for improvement

Trying to learn some new frameworks while preparing for Google I/O and helping developers to launch apps on our updated API all within a few weeks was a lot to take on. A few corners were cut and there are a few things I’d like to revisit when time permits:

  • Tests! AngularJS boasts testability as one of its key features and leverages dependency injection throughout to help keep things simple and testable. Since this was originally intended as a live demo instead of a reference app, I cut a few corners here. Yeah, I know better than that...
  • Rethink how ACE is used. In most cases it’s easy to figure out if something should be a controller, directive, filter, or service. But trying to pigeonhole libraries like ACE into one of those is daunting. Out of expediency, I chose to hide ACE behind a service, but it feels like it belongs in a directive. It would be nice to be able to declare in HTML:
    <editor content=”myModel.text”/>
    and have that sync with the model just like any other input in Angular. I started down that route, but correctly wiring up ACE to do that was more effort than it seemed worth at the time. This resulted in some other warts with how the app’s routes & views are structured.
  • Talking to the backend servers. Not so much an issue with Angular, but rather with a late decision to replace the DrEdit UI. The original goal was a separate app. Once we decided to build on the previous sample, I didn’t want to make unnecessary changes to the server side code that was already written. This led to implementing some of the new features in less than ideal ways. For example, the editor can not independently save metadata from the document content when the file is renamed or starred but the content left untouched. A minor inefficiency, but something that could have been done better.

I know I’ve only scratched the surface and have a lot more to learn. Even so, it was incredibly fun diving head first into AngularJS, and I highly recommend considering it if you’re dissatisfied with your current framework or just want to learn something new!



Steven Bazyl   profile | twitter | events

Steve is a Developer Advocate for Google Drive, Google Apps, and the Google Apps Marketplace. He enjoys helping developers find ways to integrate their apps and bring added value to users.

New Image Metadata for the Google Drive SDK

Thursday, October 25, 2012 | 10:33 AM

Labels:

Do you like to store photos in Google Drive? You are not alone! Photographs are one of the most common file types stored in Google Drive. The Google Drive API now exposes Exif data for photos, so that Google Drive Apps can use it. The Exif data contains information about camera settings and photo attributes.

Despite being an awful photographer, I love photographing benches, and here is one I took while at the beach. Let’s have a look at some of these new fields for this photo.

When I examine the metadata for this image using a drive.files.get call, there is now a field, imageMediaMetadata, containing the detailed photo information:

"imageMediaMetadata": {
  "width": 2888,
  "height": 1000,
  "rotation": 0,
  "date": "2012:07:08 15:22:25",
  "cameraMake": "NIKON CORPORATION",
  "cameraModel": "NIKON D90",
  "exposureTime": 8.0E-4,
  "aperture": 5.6,
  "flashUsed": false,
  "focalLength": 105.0,
  "isoSpeed": 200
 }

So whether you are just storing your amateur snaps like me, or using Google Drive to store serious photographs, we hope this will be useful information for Drive apps. For example, a photo organizing application will be able to create thumbnail and information views for photos without ever having to download them.

For more information, please visit our documentation, and if you have any technical questions, please ask them on StackOverflow. Our team are waiting to hear from you.

Ali Afshar profile | twitter

Tech Lead, Google Drive Developer Relations. As an eternal open source advocate, he contributes to a number of open source applications, and is the author of the PIDA Python IDE. Once an intensive care physician, he has a special interest in all aspects of technology for healthcare

Thumbnails for your Custom File Types

Thursday, October 18, 2012 | 11:24 AM

Labels:

Whenever you upload a file to Google Drive, we try to be smart and understand more about the new file. We index its text content, generate thumbnails and even use Google Goggles to recognize images. However, as any kind of files can be uploaded to Drive, there are cases where it is impossible for Drive to understand what the file content is. For instance, when inserting or updating a shortcut, the file content is not known to Drive and a thumbnail can’t be automatically generated.

Developers can now use the Google Drive SDK to provide thumbnail images for those files. The new thumbnail property on the File resource includes two sub-properties that you can set when uploading a new file or updating an existing one: “image” to contain the base64-encoded image data and “mimeType” to specify one of the supported image formats: “image/png”, “image/gif”, or “image/jpeg”.

As thumbnails must reflect the current status of the file, they are invalidated every time the file content changes, so your application should make sure to always upload a new thumbnail together with the updated content.

For more information and to learn about all requirements and recommendations about this new feature, please refer to the Uploading thumbnails section of the Google Drive SDK documentation, and don’t hesitate to ask us your technical questions!

Claudio Cherubino   profile | twitter | blog

Claudio is an engineer in the Google Drive Developer Relations team. Prior to Google, he worked as software developer, technology evangelist, community manager, consultant, technical translator and has contributed to many open-source projects. His current interests include Google APIs, new technologies and coffee.

Storing Items in Drive - BLOBs vs. Shortcuts

Tuesday, October 16, 2012 | 12:38 PM

Labels:

The Drive SDK allows apps to store all kinds of files and file-like items in user-managed cloud storage. Files can be standard document formats like PDF, images, video & audio clips, or even your proprietary application data files. Storing files in Drive makes it easy for users to organize, search, and securely share them with their coworkers, friends, or family.

However, some applications work better with document or application data stored in a database. For example, let’s imagine a modern, web-based project management tool that provides lots of awesome features via data objects that are assembled dynamically at runtime for presentation to the user. In such cases, there is no single file to store all the data that comprises the project -- though there is of course a named “file” item that users will want to save and list in their Drive. Drive applications like this can create file-like entries called shortcuts that allow users to organize, access, and share items as if they were files stored in Drive.


Creating Shortcuts

Creating a shortcut is not much different than creating a regular file. Just set the MIME type to application/vnd.google-apps.drive-sdk, and make sure you don’t upload any actual content in the call to files.insert. Here’s an example of creating a shortcut using Python:

shortcut = {
    'title': 'My project plan',
    'mimetype': 'application/vnd.google-apps.drive-sdk',
    'description': 'Project plan for the launch of our new product!'
  }
  file = service.files().insert(body=shortcut).execute()
  key = file['id'] # Key to use when re-opening shortcuts

For examples in other supported languages, see the Drive SDK documentation.

Opening shortcuts in Drive always launches the application that created them. Shortcuts can even be synchronized to the desktop. Opening a shortcut from the desktop will launch the application that created it in a new browser tab.


Sharing and Security

Shortcuts require special consideration when it comes to sharing and security. Since the actual content is not stored in Drive, applications are responsible for enforcing permissions and ensuring that only authorized users are allowed to read or update content. Follow these best practices when working with shortcuts:

  • Always call files.get with the current user’s access token to verify the user has access to the content.
  • Restrict user actions based on the userPermission property of the file and disable saves if the user only has reader or commenter roles.

Honoring permissions not only ensures the protection of user data, but also provides a consistent user experience and added value to Drive applications. Users should be able to safely share an item in Drive without worrying about the particular implementation details of the application that created it.

If you have any questions about shortcuts, don’t hesitate to ask us on our Stack Overflow tag, google-drive-sdk



Steven Bazyl   profile | twitter | events

Steve is a Developer Advocate for Google Drive, Google Apps, and the Google Apps Marketplace. He enjoys helping developers find ways to integrate their apps and bring added value to users.