This document describes how to use Google's AuthSub authentication system from a Flash or Silverlight application.
Note: If you're already familiar with AuthSub, Google's account authentication service for web-based applications, you'll see that AuthSub for ActionScript is conceptually very similar. The underlying implementation is different, but the differences aren't important to you as a client application developer. In some of the documentation, in contexts where the distinction is irrelevant, we refer to AuthSub for ActionScript as "AuthSub" for short.
The AuthSub for ActionScript interface lets Flash or Silverlight applications authenticate to protected Google Data API feeds on behalf of a user. To maintain a high level of security, the interface enables the application to get an authentication token without ever handling the user's account login information.
AuthSub for ActionScript is a variant of AuthSub for JavaScript. Like AuthSub for JavaScript, it provides a cross-domain method for client applications to authenticate from a web page hosted on a non-Google domain. It differs from the standard AuthSub in that the authentication service resides on a different domain (accounts.googleapis.com instead of www.google.com) and provides a crossdomain.xml
file allowing access to that domain from external sites.
See also the Google Accounts API Group for discussion on using all the Authentication service APIs.
Audience
This document is aimed at programmers who are developing Flash or Silverlight web applications that access Google services.
This document assumes that you understand the general ideas behind the Google Data APIs protocol and the AuthSub interface. It also assumes that you know how to program in ActionScript.
Supported environments
AuthSub for ActionScript is currently supported in Firefox 1.5 and higher and Internet Explorer 6.0 and higher, with Flash 9.0 or higher or Silverlight 2.0 or higher.
How AuthSub for ActionScript works
Here's a quick summary of how communication works between a web application, the Google Authentication service, and a Google Data service:
- To access a Google Data service on a user's behalf, the web application must have a valid authentication token. Typically, applications store this token in a cookie; if no such cookie exists, the web application must acquire the token via AuthSub. To acquire a token, the web application makes an AuthSub for ActionScript login call to the Authentication service, specifying the service to be accessed.
- On receiving the request from the web application, the Authentication service redirects the user to an "Access Request" page. This page prompts the user to log into their Google Account and asks them to grant or deny access to their Google service.
- The user decides whether to grant or deny access to the web application. If the user denies access, they are directed to a Google page rather than back to the web application.
- If the user successfully logs in and grants access, the Authentication service redirects the user back to the web application URL that made the original call. The redirect delivers an authentication token for the specified service via a query parameter. The application should store the token as a cookie in the user's browser, under the web application's domain. The token is valid until revoked. (See the About tokens section for advice about when to revoke tokens.)
- The web application contacts the Google Data service and sends the authentication token along with each request sent to the service.
- If the Google Data service recognizes the token, it supplies the requested data.
Using the AuthSub for ActionScript interface
AuthSub for ActionScript, or AuthSubAS, provides a cross-domain AuthSub endpoint for Flash (or Silverlight) applications that use Google Data APIs.
AuthSubAS provides a mirror of the AuthSub endpoints found on google.com, with an additional crossdomain.xml
file that allows Flash (or Silverlight) to access those endpoints. For example, the endpoint AuthSubSessionToken can be used by accessing https://accounts.googleapis.com/accounts/AuthSubSessionToken.
The following steps walk through the process of getting an authentication token and using it to access a Google service from a Flash application.
- Set up the cross-domain policies.
To use Flash in a cross-domain manner, it must be initialized with a policy for each external domain that is to be accessed. To do so, invoke the ActionScript method
Security.loadPolicyFile(policy)
for each domain, like so:<?xml version="1.0" encoding="utf-8"?> <Application xmlns="http://www.adobe.com/2006/mxml" initialize="onInitialized()" applicationComplete="onLoaded()"> <Script> import flash.external.ExternalInterface; import flash.net.navigateToURL; import mx.controls.Alert; private function onInitialized() : void { // Load the cross domain policy file for each of the googleapis.com // domains used. At the very least, we need the ones for the API (photos, // in this case) and the one for AuthSub for ActionScript (accounts). Security.loadPolicyFile('http://photos.googleapis.com/data/crossdomain.xml'); Security.loadPolicyFile('https://accounts.googleapis.com/crossdomain.xml'); }
Note that here we are loading the policy for
accounts.googleapis.com
(AuthSubAS) and forphotos.googleapis.com/data
(PicasaWeb, which the example accesses later). - Request a single-use token.
The first step in the AuthSub process is to request a single-use token from the AuthSub endpoint. Your application should do so by invoking a call to the
AuthSubRequest
endpoint, like so:var getTokenPage : URLRequest = new URLRequest('https://www.google.com/accounts/AuthSubRequest'); // Construct the parameters of the AuthSub request. These are the same parameters // as normal AuthSub, which can be found here: /accounts/docs/AuthSub.html#AuthSubRequest var authSubParams : URLVariables = new URLVariables(); authSubParams['scope'] = 'http://photos.googleapis.com/data'; // photos API authSubParams['session'] = 1; // single-use token authSubParams['secure'] = 0; // non-secure apps authSubParams['next'] = 'photos.swf'; // The URL of this app. getTokenPage.data = authSubParams; navigateToURL(getTokenPage, '_top');
This method requires a scope value. Each Google service defines the scope of the access it allows, and you need to reference that scope in the token request. To determine what scope value to use, check the documentation for the Google service you want to access. The scope looks like a URL; it may be a simple URL identifying the service, or it may specify more restricted access, such as limiting access to read-only. When the service offers a choice of scopes, request the most tightly scoped token possible. For example, to access Google Calendar's data feeds, use the scope
'http://www.google.com/calendar/feeds'
, not'http://www.google.com/calendar'
.Tips:
- We strongly recommend that you provide a login button or other user input mechanism to prompt the user to start the login process manually. If, instead, you check and redirect immediately after loading, without waiting for user interaction, then the first thing the user sees on arrival at your page is a Google login page. If the user decides not to log in, then Google does not direct them back to your page; so from the user's point of view, they tried to visit your page but were sent away and never sent back. This scenario may be confusing and frustrating to users.
- Applications that need to access more than one Google service for a user must request a new token for each new service (because each service has a different scope).
- Request an authentication token.
The
AuthSubRequest
endpoint will return a single-use token to your application by setting the URL of the user's browser tohttp://yourWebAppUrl?token=singleUseToken
. Once your application has received its single-use token, it must exchange the token for a multiple-usage (long-lived) token, which can then be used to make requests against Google Data feeds. To do so, call theAuthSubSessionToken
method with the single use token.Your application should check for the
token
parameter in the URL when it is loaded:private function onLoaded() : void { // Once the application has loaded, check to see if an AuthSub token was
// placed into the current page's URL. If it was, the user has already
// authenticated, and we can continue to connect to the the service itself. var searchPortion : String = ExternalInterface.call('window.location.search.toString'); if (searchPortion.length > 0) { // remove the ? from the token and extract the token. searchPortion = searchPortion.substring(1); // NOTE: Real applications should parse the URL properly. if (searchPortion.indexOf('token=') == 0) { getLongLivedToken(searchPortion.substring(6)); return; } // more code ... }If the token is found, it should call a method like
getLongLivedToken
, which invokes theAuthSubSessionToken
endpoint:private function getLongLivedToken(singleUseToken : String) : void { // Construct a call to the AuthSub for ActionScript endpoint on accounts.googleapis.com. // This call will exchange the single use token given to use by AuthSub for a long-term // token that we can use to make requests to endpoints such as Photos. var getTokenRequest : URLRequest = new URLRequest('https://accounts.googleapis.com/accounts/AuthSubSessionToken'); // Due to a bug in Flash, a URLRequest with a GET request will // not properly send headers. We therefore use POST for this and *ALL* // requests. getTokenRequest.method = URLRequestMethod.POST; // Due to a bug in Flash, a URLRequest without a valid parameter will // not properly send headers. We therefore add a useless parameter to // make this code work. getTokenRequest.data = new URLVariables('pleaseignore=ignore'); // Add the AuthSub for ActionScript headers. getTokenRequest.requestHeaders.push(new URLRequestHeader('Authorization', 'AuthSub token="' + singleUseToken + '"')); // Create the loader to get the token itself. The loader will callback // to the following event handlers if and when the server responds. var getToken : URLLoader = new URLLoader(); getToken.addEventListener(Event.COMPLETE, onGetTokenResult); getToken.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onGetTokenFailed); getToken.addEventListener(IOErrorEvent.IO_ERROR, onGetTokenFailed); try { getToken.load(getTokenRequest); } catch (e : Error) { Alert.show('Some error occurred: ' + e); }
A method like the
onGetTokenResult
handler should save the token returned:private function onGetTokenResult(e : Event) : void { // Load the parameters from the response. var getToken : URLLoader = URLLoader(e.target); var params : URLVariables = new URLVariables(getToken.data); // Parse the session token from the result. Real applications // might at this point store the token in a long-term cookie so // that repeated usages of the application do not require this entire // authentication process. sessionToken = params.Token; // Trim the newline from the end of the session token. sessionToken = sessionToken.substring(0, sessionToken.length - 1); }
Tips:
- We strongly recommend that your application stores the long-term token in a cookie, and checks them before the short-term token check; this prevents users from having to visit the AuthSub confirmation page every time they wish to use your application.
- Using an authentication token.
To use the authentication token, attach it via a
Authorization
header to any requests made to a Google service:Authorization: AuthSub token="(session token goes here)"
Example in ActionScript for the Photos service:
// Prepare a request to the photos API for the private album // of the user. var albumRequest : URLRequest = new URLRequest('http://photos.googleapis.com/data/feed/api/user/default'); albumRequest.data = new URLVariables('access=private&v=2&err=xml'); // Due to a bug in Flash, a URLRequest with a GET request will // not properly send headers. We therefore use POST for this and *ALL* // requests. albumRequest.method = URLRequestMethod.POST; var authsubHeader : String = 'AuthSub token="' + sessionToken + '"'; // Add the Authorization header which uses the session token. albumRequest.requestHeaders.push(new URLRequestHeader('Authorization', authsubHeader)); // The X-HTTP-Method-Override header tells the Photos API to treat this request // as a GET request, even though it is being conducted as a POST (due to the bug // mentioned above). This is very important, as GData APIs will react differently // to different HTTP request types. albumRequest.requestHeaders.push(new URLRequestHeader('X-HTTP-Method-Override', 'GET')); // We expect ATOM XML to be returned. albumRequest.requestHeaders.push(new URLRequestHeader('Content-Type', 'application/atom+xml'));
Google recommends providing a manual logout feature, such as a logout button or a clickable link. That approach gives users the option to log out when they choose, or to stay logged in and keep their data feeds conveniently available for the next time they access your application.
About tokens
This section describes the tokens used by AuthSub for ActionScript. In most contexts, you won't need to know this information.
Each authentication token is specific to the following data:
- Google service scope
- User's Google account
- Client application
The token data ensures that only the specified third-party application can request data and that the request is limited to data from the specified scope and user account.
Only one token for this combination of scope, user, and client can be valid at any one time. A web application must request a new token each time it needs access to a new Google service for a given user. The scope of access covered by the token depends on the Google service, which may choose to limit access to certain types of data or activity, such as read-only access.
The token returned by the AuthSub for ActionScript interface can be used as many times as is needed until it is revoked. It's up to your application to manage the life of the token, balancing security with convenience. Google recommends requesting a new token each time a new session is initiated.
Some Google services may allow access only by web applications that are registered and using secure tokens. AuthSub for ActionScript is not supported for such services. To use secure tokens, your organization must register an SSL certificate with Google and sign all requests for those data feeds.