OAuth 認証  - Firefox OS アプリプログラミング

Firefox OS 用に Twitter の OAuth 認証を実装したメモです。ポイントは、**クロスオリジン XHR 通信** です。

# 方針

## manifest.webapp の記述

クロスオリジン XHR 通信を行うためには、まず manifest.webapp の permissions に systemXHR を設定する必要があります。また、アプリケーションの type を privileged にする必要があります。manifest.webapp に以下の要領で項目を追加します。

```manifest.webapp
  "type": "privileged",
  "permissions": {
      "systemXHR": {
        "description": "for OAuth"
      }
  }
```

description に入れる文字列は、任意で良いようです。アプリケーションの type を privileged(特権付き)にするということは、Mozilla の審査が必要となることを意味するため、いろいろ面倒ですね。アプリの権限設定については、[MDN](https://developer.mozilla.org/ja/docs/Web/Apps/App_permissions) を参照してください。

## XMLHttpRequest オブジェクト作成時の引数

OAuth 認証を行うための API 通信は、XMLHttpRequest オブジェクトを用いて行われることが多いでしょう。クロスオリジンな通信を行いたい場合、XMLHttpRequest オブジェクトをインスタンス化する際の引数に、`{mozSystem: true}` というオブジェクトを渡してあげる必要があります。すなわち、

```js
XHR = new global.XMLHttpRequest();
```

というコードだった場合、

```js
XHR = new global.XMLHttpRequest({mozSystem: true});
```

のように書き換える必要があります。

# 実装

manifest.webapp に先述の記述を追加します。

次に、OAuth の実装です。今回は広く使われている [jsOAuth ライブラリ](https://github.com/bytespider/jsOAuth)を用います。このライブラリでは、XMLHttpRequest オブジェクトの生成は隠蔽されていますから、ライブラリを少し改変したうえで、ビルドしなおす必要があります。

必要な変更は、1ファイル3行だけです。差分を以下に示します。

```diff
--- a/src/OAuth/Request.js
+++ b/src/OAuth/Request.js
@@ -10,18 +10,18 @@
         } else if (typeof require !== 'undefined') {
             // CommonJS require
             try {
-                XHR = new require("xhr").XMLHttpRequest();
+                XHR = new require("xhr").XMLHttpRequest({mozSystem: true});
             } catch (e) {
                 // module didn't expose correct API or doesn't exists
                 if (typeof global.XMLHttpRequest !== "undefined") {
-                    XHR = new global.XMLHttpRequest();
+                    XHR = new global.XMLHttpRequest({mozSystem: true});
                 } else {
                     throw "No valid request transport found.";
                 }
             }
         } else if (typeof global.XMLHttpRequest !== "undefined") {
             // W3C
-            XHR = new global.XMLHttpRequest();
+            XHR = new global.XMLHttpRequest({mozSystem: true});
         } else {
             throw "No valid request transport found.";
         }
```

ビルドを行い、 ` js/jsOAuth.js `というファイル名で保存したとします。このファイルを使って、以下のように、 PIN コードベースの OAuth 認証を行うことができます。

参考：[jsOAuth boilerplate for PIN based authentication in javascript
](https://gist.github.com/bytespider/1071227)

```html:oauth.html
<html>
<head>
    <meta charset="utf-8">
    <title></title>
<script src="js/jsOAuth.js"></script>

</head>
<body>
<script>
    var config = {
        consumerKey: "YOUCONSUMERKEY",
        consumerSecret: "YOURCONSUMERSECRET",

        requestTokenUrl: "https://api.twitter.com/oauth/request_token",
        authorizationUrl: "https://api.twitter.com/oauth/authorize",
        accessTokenUrl: "https://api.twitter.com/oauth/access_token"
    };
    var oauth = new OAuth(config);

    oauth.fetchRequestToken(openAuthoriseWindow, failureHandler);

    function openAuthoriseWindow(url)
    {
        var wnd = window.open(url, 'authorise');
        setTimeout(waitForPin, 100);

        function waitForPin()
        {
            if (wnd.closed)
            {
                var pin = prompt("Please enter your PIN", "");
                oauth.setVerifier(pin);
                oauth.fetchAccessToken(getSomeData, failureHandler);
            }
            else
            {
                setTimeout(waitForPin, 100);
            }
        }
    }

    function getSomeData()
    {
        oauth.get("https://api.twitter.com/1.1/statuses/home_timeline.json", function (data) {
        }, failureHandler);
    }

    function failureHandler(data)
    {
        console.error(data);
    }
</script>
</body>
</html>
```

以上です。Twitter 以外のウェブ API でも、同様に OAuth 認証が行えると思います。