JSON Web Token の効用

**Note: JWT の仕様やそもそも論の話は触れません。どう使うか、何が出来るかしか書いていません。**

JSON Web Token?
---

JSON Web Token とは、ざっくりいって**署名の出来る JSON を含んだ URL Safe なトークン**です。
署名とは、**署名時に使った鍵を用いて、JSON が改ざんされていないかをチェック出来るようにする**ことです。
URL Safe とは、文字通り、URL に含めることの出来ない文字を含まないことです。

これだけだとよくわかりませんが、触り心地としては次のような性質があります。

1. 発行者だけが、鍵を使ってトークンが正しいことを検証出来る。
2. 暗号化ではないので、JSON の中身は誰でも見られる。
  - 仕様的には、暗号化のオプションもあります。
3. しかしながら、JSON の変更は出来ない。（改ざんをすると、検証時に失敗するので。）
4. 全体的には、**なんか変更できない JSON** だと受けとっておけばよいかと

## 使われかた

この性質のため、認証サーバなどによく使われます。簡易フローとしては、

1. クライアントは認証サーバに認証情報（よくあるのは user_id, password）を渡し、トークンを請求する。
2. 認証サーバは認証情報が正しいことを確認して、秘密鍵を使って署名された JWT を発行する。
  - この JWT は `user_id` と `expiration_date` を含む。
3. クライアントはこの JWT を使って通常の API リクエストを行なう。
4. サーバは、秘密鍵を使って JWT を検証し、`user_id` を JSON から取り出し、処理を行なう。

通常、このようなトークンを発行すると、`user_id` を書き換えるだけで全てのユーザにアクセス出来てしまう致命的なセキュリティホールを作ってしまいます。
`expiration_date` も同様で、これを書き換えるだけで無限に有効期限の切れないトークンが作れてしまいます。

しかし、JWT は「改ざん検証」が可能です。これを利用して、サーバでは検証が通らないトークンはすべて弾くようにします。そうすれば、**事前にサーバが認めた** `user_id` と `expiration_date` のみが通るようになります。

サーバは一度ユーザの認証情報を確認してからトークンを発行していますので、ここでの `user_id` は信頼でき、**ログインしているもの**と扱うことができます。

サーバが署名した情報だから、改ざんされていない（＝検証が通る）限りは信頼して使ってよいということですね。

この強力な署名の仕組みの為に、トークンに含む内容にセンシティブにならずに、標準化された方法で簡単にトークンを発行出来ることが特徴です。

実際、このような仕組みを使わずに、セキュアにトークンを発行することは大変です。
素直にやれば、トークンをランダム生成し、サーバサイドでトークンと `user_id`, `expiration_date` を紐づけてストアし、トークンを受け取るたびに毎回フェッチして `user_id` などを取り出す、という大仰な仕組みが必要になります。

**トークンに、改ざんに対して安全に情報を保持させられることは、一見地味ですが強力な性質です。**

### ユースケース

JSON Web Token は様々な利用方法がありますので、色々見ると面白いと思います。

* OAuth のトークンとして
  * Google の OAuth Token は JWT なので、Google API にトークン検証のリクエストをしなくてもトークンが検証できます。（公開鍵暗号を用いて署名していますので、クライアントには検証専用の鍵が配布されています。）
* メール認証のトークンとして
  * `scope` を `verify_email` とした `user_id` 付きのトークンを発行
* パスワード忘れメール送付時のトークンとして
  * `scope` を `reset_password` とした `user_id` 付きのトークンを発行
* サービスをまたいだ認証機構として
  * 自社のサービス間で鍵を共有することで、かんたんに独立した認証サービスを作ることができます。
* 共有用URLとして
  * `scope` を工夫することでどこまで guest に権限を持たせるかを決めることもできます。たとえば、`scope = view(album#56)` などとして `id = 56` の Album の閲覧のみが可能な URL を発行するなど。
  * ただし、URLがとんでもなく長くなるので短縮を噛ませるなど必須です。

使い勝手
---

JSON Web Token はライブラリがたくさんあります。

- Ruby: https://github.com/nov/json-jwt
- Python: https://github.com/rohe/pyjwkest
- Java: https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home
- PHP: https://github.com/ritou/php-Akita_JOSE
- Perl: https://github.com/xaicron/p5-JSON-WebToken

Objective-C もエンコード（発行）だけですが、ライブラリがあります。

- Objective-C: https://github.com/yourkarma/JWT

インターフェースとしてはどの言語も、JSON と秘密鍵を渡したらよしなにしてくれるような感じです。お手軽。
何も考えなくて良いのが JWT の良い所。

```rb
# エンコード
JSON::JWT.new({foo: "bar"}).sign(key, algorithm)
```

```rb
# デコード
JSON::JWT.decode(jwt_string, key)
```

```objc
// エンコード
[JWT encodePayload:@{@"foo": @"bar"} withSecret:@"secret"];
```

Conclusion
---

- JWT には実質改ざん不可能な情報を含めることが出来る。
  - この性質のため、認証サーバから返されるトークンに使われる。
- JWT を上手く使うことで安全な通信 / 連携を実現出来る。
- JWT を扱えるライブラリが沢山ある。
- JWT は URL Safe なので、取り扱いが楽。
- トークンはとりあえず JWT を使っておけばいいだろう、という安心感がある（私見）
- 本文では触れませんでしたが、公開鍵暗号での署名であれば「署名用の鍵」と「検証用の鍵」を分けることが可能です。JWT発行サーバには署名用の鍵を持たせ、他のサーバには検証用の鍵を持たせることもできます。

References
---

- JSON Web Tokens - jwt.io : http://jwt.io/
- JWTについて簡単にまとめてみた - hiyosi's blog : http://hiyosi.tumblr.com/post/70073770678/jwt
- JSON Web Token (JWT) - OAuth.jp : http://oauth.jp/blog/2012/10/26/json-web-token-jwt/
- JSON Web Token (JWT) - Claims and Signing : http://self-issued.info/docs/draft-jones-json-web-token-01.html