もうすぐ来る? Web Authentication APIについて調べてみた

[ピクシブ株式会社 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/pixiv) の 23 日目担当の [syoichi](https://github.com/syoichi) です。
去年の 2 月にエンジニアとして入社しました。[去年の Advent Calendar の時](http://inside.pixiv.net/entry/2016/12/14/183027)から変わらずプレミアムチームに所属しており、主に PHP / JavaScript / CSS で開発しています。直近では pixiv の決済基盤のシステムで Scala に触れる機会もありました。

さて、今回は現在各ブラウザーで開発中で、[Edge で先行実装され](https://blogs.windows.com/msedgedev/2016/04/12/a-world-without-passwords-windows-hello-in-microsoft-edge/)、[Firefox でリリースの目処が立ちつつある](https://groups.google.com/d/msg/mozilla.dev.platform/tsevyqfBHLE/lccldWNNBwAJ)、[Web Authentication API](https://w3c.github.io/webauthn/) について簡単に調べてみました。

# 何ができるのか
端的に言うと、[FIDO 2.0](https://fidoalliance.org/download/#fido20) に基いて、FIDO 対応デバイスによって指紋や顔などを照合する生体認証が Web から利用できるようになります。
活用例としては、生体認証によってパスワード無しで素早く Web サービスにログインできるようにするといったことが考えられます。既にスマートフォンやタブレットなどの一部のネイティブアプリで利用されているログイン方式に似ていますね。

# FIDO とは
Fast IDentity Online の略で、生体認証などを利用して素早くオンライン認証をする為の標準仕様の 1 つです。これまでの
 FIDO 1.0 では UAF (Universal Authentication Framework) と U2F (Universal Second Factor) に別れていましたが、FIDO 2.0 ではそれらが統合された形になりました。

# これは PWA の API なのか
[Progressive Web App Checklist](https://developers.google.com/web/progressive-web-apps/checklist) には記載されていないですが、[Web Authentication API の仕様](https://w3c.github.io/webauthn/)では PWA の API の 1 つである [Credential Management API](https://w3c.github.io/webappsec-credential-management/) との連携について言及されています。

# ブラウザーの対応状況
Edge では Windows Hello を用いて対応しているようですが、まだ最新の仕様に基づいた形で API を有効にしているブラウザーは無さそうです。

* [Chrome](https://www.chromestatus.com/feature/5669923372138496): [開発中](https://bugs.chromium.org/p/chromium/issues/detail?id=664630)
    * 主な実装: [`third_party/WebKit/Source/modules/credentialmanager/`](https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/modules/credentialmanager/), [`third_party/WebKit/public/platform/modules/webauth/`](https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/public/platform/modules/webauth/), [`content/browser/webauth/`](https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/)
        * `third_party/WebKit/Source/modules/credentialmanager/`では Credential Management API の実装と併存した形になっている
* Firefox: [開発中](https://bugzilla.mozilla.org/show_bug.cgi?id=webauthn)だが、[リリースの目処が立ちつつある](https://groups.google.com/d/msg/mozilla.dev.platform/tsevyqfBHLE/lccldWNNBwAJ)
    * 主な実装: [`dom/webauthn`](https://dxr.mozilla.org/mozilla-central/source/dom/webauthn)
    * 何故か [Firefox Platform Status](https://platform-status.mozilla.org/) に記載されていない
* [Edge](https://developer.microsoft.com/en-us/microsoft-edge/platform/status/webauthenticationapi/): vendor prefix 付きで先行実装済みだが、最新の仕様に対応するかは不明
* [Safari](https://webkit.org/status/#feature-web-authentication): まだ実装するか検討中のようだが、[対応に向けた動きがある](https://bugs.webkit.org/show_bug.cgi?id=181082)

# サンプルコード
現在も[仕様が活発に更新されている](https://github.com/w3c/webauthn/commits/master)為、サンプルコードも短期間で陳腐化しそうですが、[仕様](https://w3c.github.io/webauthn/)に記載されているサンプルコードの内、認証情報の登録と認証に関するものが以下になります。

## 認証情報の登録
``` js
if (!PublicKeyCredential) { /* Platform not capable. Handle error. */ }

var publicKey = {
  // The challenge must be produced by the server, see the Security Considerations
  challenge: new Uint8Array([21,31,105 /* 29 more random bytes generated by the server */]),

  // Relying Party:
  rp: {
    name: "Acme"
  },

  // User:
  user: {
    id: Uint8Array.from(window.atob("MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII="), c => c.charCodeAt(0)),
    name: "john.p.smith@example.com",
    displayName: "John P. Smith",
    icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
  },

  // This Relying Party will accept either an ES256 or RS256 credential, but
  // prefers an ES256 credential.
  pubKeyCredParams: [
    {
      type: "public-key",
      alg: -7 // "ES256" as registered in the IANA COSE Algorithms registry
    },
    {
      type: "public-key",
      alg: -257 // Value registered by this specification for "RS256"
    }
  ],

  timeout: 60000,  // 1 minute
  excludeCredentials: [], // No exclude list of PKCredDescriptors
  extensions: {"loc": true}  // Include location information
                                           // in attestation
};

// Note: The following call will cause the authenticator to display UI.
navigator.credentials.create({ publicKey })
  .then(function (newCredentialInfo) {
    // Send new credential info to server for verification and registration.
  }).catch(function (err) {
    // No acceptable authenticator or user refused consent. Handle appropriately.
  });
```
https://w3c.github.io/webauthn/#sample-registration

## 認証
``` js
if (!PublicKeyCredential) { /* Platform not capable. Handle error. */ }

var options = {
                // The challenge must be produced by the server, see the Security Considerations
                challenge: new Uint8Array([4,101,15 /* 29 more random bytes generated by the server */]),
                timeout: 60000,  // 1 minute
                allowCredentials: [{ type: "public-key" }]
              };

navigator.credentials.get({ "publicKey": options })
    .then(function (assertion) {
    // Send assertion to server for verification
}).catch(function (err) {
    // No acceptable credential or user refused consent. Handle appropriately.
});
```
https://w3c.github.io/webauthn/#sample-authentication

`navigator.credentials.create()`と`navigator.credentials.get()`は [Credential Management API のメソッド](https://w3c.github.io/webappsec-credential-management/#framework-credential-management)です。このように Web Authentication API は Credential Management API と連携した形で利用することになりそうです。

# デモサイト
FIDO 対応デバイスがあれば以下のデモサイトで動作を確認できるようです。

* https://webauthn.io/
* https://webauthn.bin.coffee/

# 今後の展望
各ブラウザーで開発が進んでおり、また、FIDO U2F に関しては Google、Facebook、Dropbox、GitHub などで導入されていたので、Web Authentication API が各 Web サービスで導入されるのは意外にもそう遠くない将来かもしれませんね。
ただ、FIDO 対応デバイスは普及しているとは言い難いので、生体認証自体には対応しているスマートフォンとタブレットでの利用が先行しそうです。

# 参考
* [News ＆ Trend - 認証標準化団体が「FIDO 2.0」のWeb API仕様をW3Cに提案、パスワードレス普及へ一歩：ITpro](http://itpro.nikkeibp.co.jp/atcl/column/14/346926/112300385/)
* [パスワードに代わる強固なウェブ認証実現に向けたW3Cの「Web Authentication」 - ZDNet Japan](https://japan.zdnet.com/article/35084511/)
* [Dev guide - Web authentication - Microsoft Edge Development | Microsoft Docs](https://docs.microsoft.com/en-us/microsoft-edge/dev-guide/device/web-authentication)
* [Web Authentication API 紹介 (Windows Hello を使った Edge 開発) | Tsmatz](https://tsmatz.wordpress.com/2016/06/08/w3c-web-authentication-api-javascript/)
* [Webでの生体認証をヤフーさまとともに - Windows Blog for JapanWindows Blog for Japan](https://blogs.windows.com/japan/2016/12/02/yahoojapan/)
* [Yahoo! JAPAN各サービスで、パスワードを使わないログイン方法の導入を開始 / プレスルーム - ヤフー株式会社](https://about.yahoo.co.jp/pr/release/2017/04/20a/)

# 最後に
[ピクシブ株式会社](https://www.pixiv.co.jp/)ではクリエイターに向けてサービスを作っていきたいエンジニアを募集しています!

それでは、明日からも引き続き[ピクシブ株式会社 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/pixiv) をお楽しみください。
明日の担当は @_pawa_ です。