# Authentication Drivers

This document explains the structure and functionality of a `dropbox.js` OAuth
driver, and describes the drivers that ship with the library.

## The OAuth Driver Interface

An OAuth driver is a JavaScript object that implements the methods documented
in the
[Dropbox.AuthDriver class](http://coffeedoc.info/github/dropbox/dropbox-js/master/classes/Dropbox/AuthDriver.html).
This class exists solely for the purpose of documenting these methods.

A simple driver can get away with implementing `url` and `doAuthorize`. The
following example shows an awfully unusable node.js driver that asks the user
to visit the authorization URL in a browser.

```javascript
var util = require("util");
var simpleDriver = {
  url: function() { return ""; },
  doAuthorize: function(authUrl, token, tokenSecret, callback) {
    util.print("Visit the following in a browser, then press Enter\n" +
                authUrl + "\n");
    var onEnterKey = function() {
      process.stdin.removeListener("data", onEnterKey);
      callback(token);
    }
    process.stdin.addListener("data", onEnterKey);
    process.stdin.resume();
  }
};
```

Complex drivers can take control of the OAuth process by implementing
`onAuthStateChange`. Implementations of this method should read the `authState`
field of the `Dropbox.Client` instance they are given to make decisions.
Implementations should call the `credentials` and `setCredentials` methods on
the client to control the OAuth process.

See the
[Dropbox.Drivers.Chrome source](../src/drivers/chrome.coffee)
for a sample implementation of `onAuthStateChange`.


### The OAuth Process Steps

The `authenticate` method in `Dropbox.Client` implements the OAuth process as a
finite state machine (FSM). The current state is available in the `authState`
field.

The authentication FSM has the following states.

* `Dropbox.Client.RESET` is the initial state, where the client has no OAuth
tokens; after `onAuthStateChange` is triggered, the client will attempt to
obtain an OAuth request token
* `Dropbox.Client.REQUEST` indicates that the client has obtained an OAuth
request token; after `onAuthStateChange` is triggered, the client will call
`doAuthorize` on the OAuth driver, to get the OAuth request token authorized by
the user
* `Dropbox.Client.AUTHORIZED` is reached after the `doAuthorize` calls its
callback, indicating that the user has authorized the OAuth request token;
after `onAuthStateChange` is triggered, the client will attempt to exchange the
request token for an OAuth access token
* `Dropbox.Client.DONE` indicates that the OAuth process has completed, and the
client has an OAuth access token that can be used in API calls; after
`onAuthStateChange` is triggered, `authorize` will call its callback function,
and report success
* `Dropbox.Client.SIGNED_OFF` is reached when the client's `signOut` method is
called, after the API call succeeds; after `onAuthStateChange` is triggered,
`signOut` will call its callback function, and report success
* `Dropbox.Client.ERROR` is reached if any of the Dropbox API calls used by
`authorize` or `signOut` results in an error; after `onAuthStateChange` is
triggered, `authorize` or `signOut` will call its callback function and report
the error


## Built-in OAuth Drivers

`dropbox.js` ships with the OAuth drivers below.

### Dropbox.Drivers.Redirect

The recommended built-in driver for browser applications completes the OAuth
token authorization step by redirecting the browser to the Dropbox page that
performs the authorization and having that page redirect back to the
application page.

This driver's constructor takes the following options.

* `useQuery` should be set to true for applications that use the URL fragment
(the part after `#`) to store state information
* `rememberUser` can be set to true to have the driver store the user's OAuth
token in `localStorage`, so the user doesn't have to authorize the application
on every request

Although it seems that `rememberUser` should be true by default, it brings a
couple of drawbacks. The user's token will still be valid after signing out of
the Dropbox web site, so your application will still recognize the user and
access their Dropbox. This behavior is unintuitive to users. A reasonable
compromise for apps that use `rememberUser` is to provide a `Sign out` button
that calls the `signOut` method on the app's `Dropbox.Client` instance.

The [checkbox.js](../samples/checkbox.js) sample application uses
`rememberUser`, and implements signing out as described above.


### Dropbox.Drivers.Popup

This driver may be useful for browser applications that can't handle the
redirections peformed by `Dropbox.Drivers.Redirect`. This driver avoids
changing the location of the application's browser window by popping up a
separate window, and loading the Dropbox authorization page in that window.

Most browsers will only display the popup window if `client.authorize()` is
called in response to a user action, such as click on a "Sign into Dropbox"
button. Browsers have different heuristics for deciding whether the condition
is met, so the safest bet is to make the `client.authorize()` call in a `click`
event listener.

To use the popup driver, create a page on your site that contains the
[receiver code](../test/html/oauth_receiver.html),
change the code to reflect the location of `dropbox.js` on your site, and point
the `Dropbox.Drivers.Popup` constructor to it.

```javascript
client.authDriver(new Dropbox.Drivers.Popup({
    receiverUrl: "https://url.to/oauth_receiver.html"}));
```

If your application supports Internet Explorer, the receiver code must be
served from the same origin (protocol, host, port) as your application.

The popup driver adds a `#` (fragment hash) to the receiver URL if necessary,
to ensure that the user's Dropbox uid and OAuth token are passed to the
receiver in a URL fragment. This measure may improve your users' privacy, as it
reduces the chance that their uid or token ends up in a server log.

If you have a good reason to disable the behavior above, set the `useQuery`
option to true.

```javascript
client.authDriver(new Dropbox.Drivers.Popup({
    receiverUrl: "https://url.to/receiver.html", useQuery: true}));
```

The popup driver implements the `rememberUser` option with the same semantics
and caveats as the redirecting driver.


### Dropbox.Drivers.Chrome

Google Chrome [extensions](http://developer.chrome.com/extensions/) and
[applications](http://developer.chrome.com/apps/) are supported by a driver
that opens a new browser tab (in the case of extensions and legacy
applications) or an application window (for new applications) to complete the
OAuth authorization.

To use this driver, first add the following files to your extension.

* the [receiver script](../test/src/helpers/chrome_oauth_receiver.coffee); the
file is both valid JavaScript and valid CoffeeScript
* the [receiver page](../test/html/chrome_oauth_receiver.html); change the page
to reflect the paths to `dropbox.js` and to the receiver script file

Point the driver constructor to the receiver page:

```javascript
client.authDriver(new Dropbox.Drivers.Chrome({
  receiverPath: "path/to/chrome_oauth_receiver.html"}));
```

This driver caches the user's credentials so that users don't have to authorize
applications / extensions on every browser launch. Applications and extensions'
UI should include a method for the user to sign out of Dropbox, which can be
implemented by calling the `signOut` instance method of `Dropbox.Client`.


### Dropbox.Drivers.Cordova

This driver uses Cordova's
[InAppBrowser](http://cordova.apache.org/docs/en/2.4.0/cordova_inappbrowser_inappbrowser.md.html#InAppBrowser)
to open a popup-like activity that completes the OAuth authorization.

```javascript
client.authDriver(new Dropbox.Drivers.Cordova());
```

This driver implements the `rememberUser` option with the same semantics and
caveats as the redirecting driver.


In theory, the Redirect driver should work for Cordova applications. However,
[this bug](https://code.google.com/p/android/issues/detail?id=17327) prevents
it from working on Android, so a cross-platform application should use the
Cordova-specific driver.


### Dropbox.Drivers.NodeServer

This driver is designed for use in the automated test suites of node.js
applications. It completes the OAuth token authorization step by opening the
Dropbox authorization page in a new browser window, and "catches" the OAuth
redirection by setting up a small server using the `https` built-in node.js
library.

The driver's constructor takes the following options.

* `port` is the HTTP port number; the default is 8192, and works well with the
Chrome extension described below
* `favicon` is a path to a file that will be served in response to requests to
`/favicon.ico`; setting this to a proper image will avoid some warnings in the
browsers' consoles

To fully automate your test suite, you need to load up the Chrome extension
bundled in the `dropbox.js` source tree. The extension automatically clicks on
the "Authorize" button in the Dropbox token authorization page, and closes the
page after the token authorization process completes. Follow the steps in the
[development guide](./development.md) to build and install the extension.
