The Implicit Grant flow for browser-based client-side web applications is very simple. In this flow, an access token is immediately returned to the application after a user grants the requested authorization. An intermediate authorization code is not required as it is in the server-side Web Application flow (see Chapter 2).
Figure 3-1 shows a step-by-step flow diagram, based on a diagram from the specification.
The Implicit Grant flow should be used when
Only temporary access to data is required.
The user is regularly logged into the API provider.
The OAuth client is running in the browser (using JavaScript, Flash, etc.).
The browser is strongly trusted and there is limited concern that the access token will leak to untrusted users or applications.
The Implicit Grant flow does not accommodate refresh tokens. If the Authorization server expires access tokens regularly, your application will need to run through the authorization flow whenever it needs access.
Some API providers, such as Google, will not reprompt the user for access if the user remains logged in and has approved the required scopes previously. The application can do this “refresh” process in the background as an iframe without any impact on the user experience.
In the Implicit Grant flow, the application does not store long-lived refresh tokens on a server, limiting the exposure if the server is compromised. It also requires that the user be authenticated to the API provider’s authorization server in order to “refresh” access tokens on the client, ensuring that a leaked access token’s value is time-limited, depending on the OAuth implementation.
Because the access token is sent to the user’s web browser, this flow offers less accountability than the Authorization Code flow. API calls that appear to have originated from a third-party app may have in fact been made directly by the resource owner themselves.
A JavaScript-based Contacts picker for selecting users to invite to a Photo Viewer application is a great example use case for the Implicit Grant flow. It is a valuable activity for both the user and the application developer, it doesn’t happen regularly, and the user is always responsible for choosing which users to invite from his or her contacts.
The user experience is identical to the Server-Side Web Application flow described in Chapter 2:
Photo Viewer application lets the user know that it needs access to her Contacts.
The OAuth authorization server used by the Contact app’s API prompts the user to grant permission for the Photo Viewer application to read her contacts.
After the user has approved, she is redirected back to the Photo Viewer application, which now has access to her contacts.
Like in the case of the flow for Server-side Web Applications described in Chapter 2, you’ll first need to register your application with the API provider (see Developer and Application Registration).
After registration is complete, it’s time to write some code! We’ll use simple HTML and JavaScript for this example.
This step is very similar to the Authorization Code flow. Since requesting data access requires redirecting your users to the authorization server, it’s a best practice to let them know in advance what will happen. You can do this by displaying a message, along with a link that directs the user to the OAuth authorization endpoint.
You can find the URL for the OAuth authorization endpoint in the API provider’s documentation. For Google Tasks (and all other Google APIs using OAuth 2.0), the authorization endpoint is at
https://accounts.google.com/o/oauth2/auth
You will need to specify a few query parameters with this link:
client_id
The value provided to you when you registered your application.
redirect_uri
The location the user should be returned to after they
approve access for your app. For this example, the application
will use https://photoviewer.saasyapp.com/oauth_response.html
.
scope
The data your application is requesting access to. This is
specified as a list of space-delimited strings. Valid values for
the scope
should be included in
the API provider documentation. For Google Contacts, the scope
is https://www.google.com/m8/feeds/
.
response_type
The token
for the
client-side Web Application flow, indicating that an access token
will be returned to the application after the user approves the
authorization request.
The complete code for handling this flow (in index.html
) is long, so let’s explore it in
snippets.
This initial snippet opens a pop up window to the authorization
URL. The client_id
, scope
, and response_type
are set to the appropriate
values. A pseudo-random state value is generated in order to mitigate
the risk of CSRF attacks. We’ve also set the redirect_uri
to a page that contains
JavaScript for parsing the access token from the URL and passing it back
to the parent window:
<script type="text/javascript"> var clientId = '1032068783357.apps.googleusercontent.com'; var authorizationUrlBase = 'https://accounts.google.com/o/oauth2/auth'; var redirectUri = 'http://photoviewer.saasyapp.com/pv/oauth2callback.html'; var scope = 'https://www.google.com/m8/feeds/'; var state; function startOauth() { // generate a pseudo-random number for state var rand = Math.random(); var dateTime = new Date().getTime(); state = rand * dateTime; var url = authorizationUrlBase; url += '?response_type=token' + '&redirect_uri=' + encodeURIComponent(redirectUri) + '&client_id=' + encodeURIComponent(clientId) + '&scope=' + encodeURIComponent(scope) + '&state=' + encodeURIComponent(state); var w = window.open(url, '_blank', 'width=500,height=400'), } </script>
See the description for error handling in Step 1 of the Server-side Web Applications flow (Chapter 2). The same error handling process applies to this flow.
After the user approves access, the pop up window is redirected
back to the specified redirect_uri
and an access_token
is included in
the #
hash fragment. Here’s an
example URL for this application:
http://photoviewer.saasyapp.com/pv/oauth2callback.html#access_token=ya29.AHES6ZSzX&token_type=Bearer&expires_in=3600
JavaScript doesn’t traditionally treat elements of the hash
fragment as name/value pairs, so we need to parse out the value of the
access_token
and other elements of
the OAuth response:
var oauthParams = {}; // parse the query string // from http://oauthssodemo.appspot.com/step/2 var params = {}, queryString = location.hash.substring(1), regex = /([^&=]+)=([^&]*)/g, m; while (m = regex.exec(queryString)) { oauthParams[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); } ...
Next, we need to pass the access token to the parent window:
window.opener.setOauthParams(oauthParams);
This passes the access token back to the main browser window. To
protect against CSRF attacks, the setOAuthParams
method should check that oauthParams['state']
matches
the global state variable set in startOAuth
above.
This mechanism of communicating with the parent window works in modern browsers. However, the same-origin policy is enforced, so the pop up window needs to match the host/port/protocol of the main window.
Google has implemented a more elegant way for OAuth 2.0 pop up
windows to communicate using the HTML5
window.postMessage
feature. This is not widely
deployed yet, but you can see a sample
implementation on Google Project Hosting.
We use jQuery for calling
the API to make it a bit easier. Instead, you could create a <script>
element pointing to the JSONP
URL for the Contacts API and dynamically append it to the <head>
element of your webpage.
The callApi()
function below
will retrieve the user’s contacts as JSON and call the setResponse
function with the data:
function callApi() { var contactsUrl = 'https://www.google.com/m8/feeds/contacts/default/full?v=3.0&alt=json-in-script'; document.getElementById('access_request').style.display = 'none'; var oauthParams = this.getOAuthParams(); contactsUrl += "&access_token=" + encodeURIComponent(oauthParams['access_token']); $.ajax({ 'url': contactsUrl, 'dataType': 'jsonp', 'success': function(data) { setResponse(data); } }); }
Notice that we appended the access_token
to the URL instead of using the
preferred Authorization
header
mechanism. This is because jQuery does not allow manually setting the
Authorization
header used on these
requests.
Unlike with the Authorization Code flow for server-side web applications, there is no special protocol for refreshing tokens when using the Implicit Grant flow. Your application will simply need to request a new access token using the same process as you used to fetch the initial token (Steps 1 to 3 above).
Some providers, like Google, will not present an authorization request to the user if they have previously approved access for your application. However, the user will need to be logged into their Google account for a new token to be issued without the authorization server prompting the user for their Google account password.
Although not standardized yet, support for an “immediate” mode also exists in some OAuth 2.0 providers. This allows this refresh process to occur in a hidden iframe, enabling a new access token to be transparently sent back to the application without the risk of prompting the user. If the user would otherwise be prompted to authenticate or grant access, immediate mode will instead cause the window to be redirected back to the app with an error message indicating the failure. This allows the app to gracefully prompt the user as needed for renewed authorization.
For the Google and Salesforce OAuth authorization endpoints, you
can provide an additional query parameter value
immediate=true
to enable immediate mode.
See the description for token revocation in the Server-side Web Applications flow (Chapter 2) section. The same token revocation process applies to this flow.
3.145.40.189