nappsについてのメモ

一部界隈で最近よく名前を聞くnappsについて調べてみたので、自分の理解のためにまとめます。

nappsとは

nappsとはNative Applications WGのことでモバイルのネイティブアプリでのSSOをOpenID Connectで実現するprofileを策定しています。(native(n) applications(apps)でnappsなんですかね?)

nappsでは、例えばスマートフォン複数のネイティブアプリがインストールされていて、かつそれらがOAuthによるリソースアクセスとOpenID Connectによる認証を行う場合、複数のネイティブアプリ全てで認証と認可の管理が必要になってユーザビリティ的に厳しいよねという問題を解決するとしています。各アプリで認証するとかなっているとユーザビリティ的にもセキュリティ的にもつらいですね。

で、どうやってこの問題を解決するかというと、あるアプリをToken Agent(TA)と呼ばれる他のアプリの代わりにtokenを取得する特別なclientとし、TAを経由して他のアプリはtokenを取得するとしています。このTAによってtokenのprovisioningとSSOを実現します。TAでのみ認証させるようにすることでフィッシング防止にもなるかなーと思います。

リポジトリを見た感じ、nappsでは今のところ仕様は2つあるみたいです。

  • OpenID Connect Native Application Token Agent Core 1.0
  • OpenID Connect Native Application Token Agent API Bindings 1.0

1つがcoreとなる仕様で、もう1つはTAと他のアプリの間でのやりとりに関する仕様のようです。

語彙

OpenID Connectの語彙に加えて、いくつか語彙が加わっています。

  • Token Agent (TA)
    • その他のアプリに変わってaccess tokenなどを取得するアプリのことで、Authorization Serverごとにユーザーはこのアプリでのみ認証をします
  • Primary Token
    • TAに発行されるaccess token, refresh token, id_tokenのこと
  • Secondary Token
    • その他のアプリに発行されるaccess tokenのこと
  • AppInfo Endpoint
    • TAがアプリのメタデータを取得するエンドポイントで、取得されたメタデータはその他のアプリのSecondary Tokenを取得するために使われます

フロー

Native Application Token Agent Coreでは以下のようなフローが想定されています。

f:id:bang_yy:20141102031557j:plain

省略して書いてありますが1,2は普通のOpenID Connectのフローです。このステップではTA自身に発行されるPrimary Tokenを取得します。ただし、1,2のOpenID ConnectのフローはAuthorization Flowでなければならず、Authorization Endpointではresponse_typeにcodeを、scopeにopenidとnappsという文字列を含めるようにします。napps scopeはTAがSecondary Tokenの取得に使用できるtokenを要求していることを示しています。

3,4でTA以外のアプリのSecondary Tokenを取得しています。TAからのリクエストは以下のようになります。Secondary Tokenはrefresh tokenを使って取得します。scopeに指定する値は後で出てくるAppInfo Endpointで得られるアプリごとの文字列で、scopeの値でSecondary Tokenを発行するアプリが指定されます。

POST /as/token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8

grant_type=refresh_token&
  refresh_token=qANLTbu17rk17lPszecHRi7rqJt46pG1qx0nTAqXWH&
  scope=urn:oauth:boxx

レスポンスとしてaccess tokenもしくはid_tokenを受け取ります。id_tokenを受け取った場合はさらにid_tokenとaccess tokenを交換することになるのですが、そのケースについてはTBDとなっていました。アプリがTAにSecondary Tokenを要求する部分についてはapi bindingsで規定されるとのことです。

5でTokenの受け渡しをします。ここについてもapi bindingsで規定されるようです。

6でアプリからResource ServerにSecondary Tokenを使ったAPIリクエストをしています。さらに、このリクエストを受けて、Resource Serverは7のaccess tokenの検証を行います。access tokenの検証を行います。検証の方法は規定されていませんが、tokenの検証をAuthorization Serverに依頼したり、tokenのsignatureをResource Server内で検証するなどが例に出ています。

AppInfo Endpoint

また、Native Application Token Agent CoreではAppInfo Endpointというエンドポイントが存在しています。このエンドポイントにリクエストすることで、TAを利用してaccess tokenを取得するアプリのメタデータを取得できます。AppInfo Endpointへのリクエストはaccess_tokenとschemeの2つのパラメータを指定して、GETもしくはPOSTでリクエストします。access_tokenにはTAが取得したaccess_tokenを、schemeには"napps"という文字列を指定します。GETだとこんな感じになります。

GET /appinfo?scheme=napps HTTP/1.1
Host: server.example.com
Authorization: Bearer SlAV32hkKG

レスポンスはjsonで、以下のようなメタデータが返ります。

{
    "schema": "http:openid.net/schema/napps/1.0",
    "branding": {
        "companyname": "ABS",
        "companyiconurl": "http://www.ABS.com/logo.gif"
    },
    "apps": [
            {
                "name": "Boxx",
                "type": "native",
                "scope": "urn:oauth:boxx",
                "default_scopes": ["read" , "admin" ],
                "icon_uri": "http://www.example.com/pic.png",
                "custom_uri": "app1://callback-uri/"
            },
            {
                "name": "test1",
                "type": "web",
                "scope": "urn:oauth:test1",
                "default_scopes": ["urn:oauth:web-sso"],
                "icon_uri": "http://www.example.com/pic.png",
                "web_init_ep": "http://init-sso.example.com/start"
        ]
}

レスポンスの中身は以下のような内容になっています。

  • name
    • アプリの名前
  • type
    • アプリのタイプ(nariveかwebとなります)
  • scope
    • Secondary Tokenを取得する際に指定するscopeの値
  • default_scopes
    • アプリから明示的な指定がない場合、Secondary Token取得時にscopeパラメータに加える値
  • custom_uri
    • TAからアプリに戻る際のcustom scheme URI

AppInfo Endpointで得られるメタデータは、ランチャーのようにしてユーザーにアプリの情報を表示するのに使用したり、Secondary Tokenを取得する際に使われます。

感想

いろいろ資料を見ているとエンプラ向けの仕様なのかな?と思いました。LINEやFacebook的な、母艦となるアプリケーションが存在する場合でも有効そうなフローだとは感じます。

JICS2014 Day2 レポート

先週の1/14、15にJICS2014というカンファレンスが開催されました。両日参加したかったのですが、2日目のみの参加になってしまいました。

そんなわけで、以下2日目に自分が聴講した講演のメモです。

ID基盤構築101 - 伊藤忠テクノソリューションズ 富士榮 尚寛さん

  • 頑張らないシステム化についての話
  • ID基盤が無いと...
    • それぞれのWebアプリとかがID管理を行うことになる
    • 認証機能/DBをそれぞれで用意するので、開発側もユーザー側もコスト増
    • 組織が変わった時とか、すべてのDBで操作が必要になる
  • ID基盤を導入すると...
    • 統合認証、統合データベース、プロビジョニング
    • 統合認証システムで開発効率向上
    • 監査も簡単になる
  • ID基盤が何かって難しいし説明しにくい
  • ID基盤導入のモチベーションの例
  • ついでにやりたいことが出てくる
    • リソース管理だとかロール管理
    • それID基盤でやることじゃない
  • スモールスタート、プロトタイピングしよう
  • クラウドの仕様は良く変わる
    • プロトタイピングしたほうがいい

ビッグデータアイデンティティ - 国立情報学研究所 佐藤 一郎さん

  • ビッグデータとID(識別子)について
  • モノのidの仕事をしてきた
    • RFIDとか
    • 今回はそういった話
  • 専門はOSとかミドルウェアとか、低レイヤなところ
  • 商品とID
  • 標準化に先にコミットした国ほど多くの国コードが割り当てられている
  • 商品バーコードが生まれた理由
    • スーパーのレジ待ち解消
    • 当初はスーパーごとに商品にバーコードを貼り付け
    • スーパー間でバーコードを共通化
    • 予め商品につけた
    • 全米で共通化したのち世界共通化
  • JANコードは商品と商品に関する情報(販売価格など)をつなぐリンク
  • JANコードがない商品は流通しない(存在しないと同じ)
    • JANコードがあっても、商品情報がなければ販売しない
  • JANコードの製造者番号 = 商品について責任を取る先
  • 書籍にはISBNのバーコードもついてる
  • 書籍は再販制度により定価販売なので、書籍JANコードに価格を含めている
  • JANコードを使ってA/Bテストはできるか -> パッケージの見た目が変わったぐらいではJANコードは変えられない
    • パッケージの外寸とかが変わった場合はJANコードの変更が可能
  • IDは関心ごとによって付けられる
    • 商品の印刷デザインはJANコードの関心事ではない
    • 公的な番号を民間利用しようとすると不便がある場合がある
  • コンピュータは現実世界を直接扱えないので、現実世界の対象にIDを付番してそのIDを扱う
  • ビッグデータ分析と言う前に対象に適切にIDを振ることが第一歩
    • 関心ごとに応じて対象にIDを付番するのが第一歩
  • モノのID
    • 自動車番号
    • 製造番号
      • 生産日次、ライン番号がわかれば十分
  • 大根とかにも一個一個ICタグを振るという話もあった
    • 必要性が殆ど無い
  • 現実社会はID社会と言ってもいい
  • IDを変えることで世の中も変えられる

プライバシーとアイデンティティ - OpenID Foundation 崎村 夏彦さん

  • プライバシーって何?
    • privacy = private + -cy
  • 個人情報であっても公知であるものはプライバシーの範疇ではない
  • right to be let alone
  • 個人の不可侵の権利
  • 自己に対する自己の主権、すなわち人間の自由の権利
  • "損害賠償に依る救済を与えるルール(プライバシー侵害があれば事後的に金銭賠償で救済)"から"物件としての救済を与えるルール"へ
  • 自分に属する情報は自分がどう使うか決めていい -> アイデンティティ連携
  • identityとは
    • ある実態に関連した属性の集合
      • = パーソナルデータの部分集合
  • アイデンティティ連携 = 誰に、何のために、何を提供するかを同意する
  • 騙して使う例
    • お客に正直なことを行ったら同意してもらえない -> お客の利益にならないことをやろうとする
    • 目的の限定なんて出来ない、後から同意の取得なんて出来ない -> 20世紀的発想
    • バレたら炎上
  • ISO/IEC 29100のプライバシー原則
  • 明示的同意?
    • 常に要求するのが正しいのか?
  • そもそも同意の向きが逆
    • 企業が同意する
  • 個人によるプライバシー侵害
    • 見なかったことにするプライバシー
    • MACアドレスとか取れちゃうけど捨てる、とか
  • リスペクト、せよ!
    • 人間(ユーザー)をリスペクトすることが大切

パーソナルデータ利活用の最前線

Twitterのデータ提供と活用 - Twitter Japan 牧野 友衛さん

  • メディアからの報道からユーザーによる発信へ
  • モバイルからのアクセスが75%以上
    • 元々SMSからの利用を想定していた
  • 情報利用とプライバシー保護
    • サインアップはメールアドレスがあればできる
      • TEL、住所等は不要
    • Twitterは公開前提で利用
      • プロテクトアカウントも存在するけど割合は低い
    • 利用許諾での事前許諾の明示
      • 利用規約5章のユーザーの権利で他社のコンテンツ利用について記載
    • Display Guideline
    • TV局がユーザーの許諾なく使えるようにガイドラインを整備
      • 番組での利用: 公開APIを無料で利用可能
  • 国内だとNTT DataがTweet Dataの再販売をしている
  • 利用例
    • ヒカリエ内のShinQsをオープンする際、オープン1ヶ月前とその後のユーザーの生の声を把握
    • Ponta
      • キャンペーンで利用
    • 自民党
      • 国民の声を把握、情報発信の方向性決めや、誹謗中傷・デマ対策
    • 朝日新聞毎日新聞
      • 選挙時の分析に利用
    • 震災ビッグデータ
    • QUICK端末にも利用
      • ポジ・ネガの投稿件数を把握
    • 視聴率的に利用

楽天のデータサイエンスによるEC革命 - 楽天 北川 拓也さん

  • 楽天amazon
    • top pageはそんなにデザインも違わないのでは?
    • item pageは大分違う
      • 楽天は長い(20ページぐらいあるやつもある)
    • amazon: 値段、送料、配送日が目立つ
      • 理性的なアピール
    • 楽天: タレント、共感、効能
      • 感情価値へのアピール
  • 感情価値のほうが大事なのでは?!
    • 感情価値の向上をあらゆる領域で
  • 楽天はBtoBtoC
    • 楽天(B) -> 店舗(B) -> ユーザー(C)
  • サービス向上
    • Google: テクノロジーによる情報の質向上
    • 楽天: テクノロジーによる購買の質向上
  • 買ったものに幸せを感じる人と買うことを幸せに感じる人がいる
    • 購買体験そのものを売る
    • 楽天オンラインショッピングでデートしよか?」
  • 感情価値が買い始める理由となる
    • eコマースを盛り上げる
  • IDがあれば欲しいものがわかる

ID連携の広がりとともに増すセキュリティの重要性 - 株式会社野村総合研究所

  • ID統合ではなくID連携
  • 企業間ID連携によって、異業種間のID連携をすることで価値を生み出す
  • 価値が高まると攻撃対象となる可能性も高くなる

2020年のポイントサービス - パネルディスカッション

将来のポイントサービスはどう進化するのか

  • 安岡さん
    • 最終消費支出: 234.4兆円
    • 登録の簡便さよりもインセンティブ(ポイント)やアフターサービスなどのメリットがあることを重視している
    • ポイント導入のメリットは顧客囲い込み、優良顧客化、新規顧客獲得、相互総客
    • 値引きではなくポイントなのは、ポイントのほうが誘引効果が高いから
  • 前さん
    • 70年代: 共通スタンプカード
    • 90年代: ポイントカード
    • 電子マネー決済に依るポイント付与(FeliCa, おサイフケータイ), エコポイント
    • 電子クーポン(O2O)
    • 2020年はマイナンバー, IFRSによって変わるのでは
    • カード媒体の変遷
      • 紙->時期->リライトカード->非接触IC
    • 自社ポイント vs 共通ポイント
    • インセンティブ
      • スタンプ vs ポイント vs クーポン
    • 運用コスト
      • ローカルvsサーバ
  • 北川さん
    • ポイントの収集は日本人特有のものかもしれない
    • 特別ポイントの親和性の高いビジネス = カード・決済ビジネス
    • 価格競争になってしまってはいけない
      • 値引きとしてのポイントシステムではいけない
    • ライフスタイル・ライフステージに応じたサービス提供が必要
  • 池谷さん
    • 世界中にポイントカードは存在する
      • Nector(イギリスで1850万人会員がいる)とか世界中にも色々
      • air milesが共通ポイントの成り立ち
    • 精度の高い顧客情報の収集と分析に注力
    • 顧客はもちろん提携先の満足度向上
    • 地域通貨をポイントに変えて寄付とかの活用も進むかも

過去のポイントのそもそもの役割は?

  • 90sに紙スタンプカードからポイントカードに変わったことによって顧客識別が可能に
  • 楽天カードに加入したらポイント付与とかは、最近やりはじめたことなのでは

現在のポイントはどうか?

  • 共通 or 独自
    • 企業側は困ってる
      • インセンティブ、価格競争が潜在化してる
      • インセンティブとかやめても実際は変わらないのでは
      • インセンティブにしか興味ないユーザーを育成してしまってる
  • 今は囲い込みではなく、識別できた結果を上手く使わないといけない段階
  • 価格よりリテンション
  • 獲得施策としてポイントを使う
  • IDの普及によって決済手段として使えるようになってきた
  • リアルとネットの融合ってまだまだだよね
  • 会場だと、Tポイントカード持っている人が全体の半分、PontaもRも半分ぐらいいる
    • だいたいみんな全部もってるのでは
  • ビッグデータとポイント
    • ポイントとの関係っていうのではなく、IDとの関係
    • 将来的にはポイントがbitcoinのような通貨に統合されるかも

未来のポイントはどうか?

  • ポイントシステムの引き合いの波はある
    • ポイントカードの引き合いは、今は減少してる感じ
    • このままでいいのかな、って企業は思っているのでは
    • 今はクーポンの引き合いの方が多い
  • スマホとポイントの融合をどうするか
  • 走ったこと(ランニング)に対してクーポンもらえるみたいなベンチャーはUSにすでにある
  • ポイントからの脱却をしないといけない(北川さん)
    • ポイントは使い続けるけど、頼らないようにする

情報銀行とパーソナルデータシステム - パネルディスカッション

  • モデレーター
    • 崎村 夏彦さん
  • パネリスト

  • 崎村さん

    • 個人からの同意を得ることは不可能と思い込んで無断で使っている現状
      • 本人にアクセスすることは不可能と思っている
        • この想定は古臭い
      • この前提を切り替える
    • OpenID
      • IdPに属性を集約
      • 古典的コンシューマIdPモデル
      • ユーザーの同意を元に同意済みデータをサービスに渡す
      • 後から拒否もできる
      • 課題
        • 広告モデルで成り立つIdPでは、ユーザーとIdPの間に利益相反がある
        • パーソナルデータの利用目的がわかりにくいため有効な同意をユーザーができない
    • OpenPDS(Personal Data System)
      • 予めPDSに同意のルールを設定しておく
        • de-personalizedしてpublicに出すことも出来る
  • 情報銀行とは(砂原さん)

    • パーソナル情報を信託して預ける仕組み
    • 銀行はメタファー
      • パーソナルデータを資産として扱うのは筋が良くないかもというのはある
    • bigdataの利活用
      • 本当にやりたいのは統計データの活用ではなく、個人のために、個人の情報を使って活用する
    • 情報漏洩や不正利用の問題を解決するために正しく利用するための基板が必要
    • パーソナルデータは今は企業のものになってしまってる
      • 個人が企業の許可なしに使えない状態
    • パーソナルデータは企業と個人の共有物
    • パーソナルデータが総合化される
      • 総合化されたデータを信託する場所 -> 情報銀行
    • 社会受容性が一番大事
  • mitkitのpdsとの違いは?

    • そんなに違わない
      • しかし日本には素晴らしい技術者がいる = 高木さん
      • 高木さんに文句を言われないようなシステムを作る
      • みんなが納得してくれるのが大事
    • pdsとも連携したい
    • interoperabilityは大事(崎村さん)
    • pdsでは毎回同意を取るのは大変だから事前にルールを作っておいて毎回同意を求めないようにしている。情報銀行ではどう?(崎村さん)
    • プライバシー面からの課題は?(崎村さん)
  • 個人情報保護法改正について(佐藤さん)

    • IT総合戦略本部パーソナルデータ検討会技術WGの論点
    • 個人情報を第三者に提供するときは本人からの同意を得る必要がある
      • 情報を預かった事業者から別の事業者にデータを渡すときも
      • 今は匿名化するなどして渡している
    • 安全な匿名化
      • そんなものはない
    • 匿名性の高低はあるけど、完全なものはない、ケースバイケースである
      • 安全なレベルはあるのでは
        • そんなものもない
    • 再識別の禁止をする
      • 再識別の困難性
        • これのレベルを定めた
    • 識別を特定を分けて考える
    • パーソナルデータの利活用は刃物の取り扱いのようなもの
    • まとめ
      • 匿名化、統計化に安全基準はない
      • ビジネス要求がなければ議論できない
      • 提供先の禁止義務の監視は難しい
    • ターゲットマーケティングにおいても個人を特定する属性情報の入手は必須ではない
  • 現在の法律では第3者提供ができないから緩和しないといけないけどゆるゆるだといけない

  • 基本サービスを享受するために個人情報を利用することが当然のような場合は同意を求めないほうがいいのでは?という話がWGでもでた(佐藤さん)
    • 極端な例なのでコンセンサスは取れなかった
  • データが漏れてしまった時の責任を考えておく必要がある(砂原さん)
  • まとめ
    • 情報銀行のビジネスモデルについて(砂原さん)
      • 楽天やCCCとかより、自動車屋とかが情報銀行を使いたいと考えるのでは?
      • まだビジネスになるかはわかっていない
    • 佐藤さん

グローバルクラウド時代のアイデンティティとデータの所在

  • モデレーター
    • KDDI(株) 藤井 彰人さん
  • パネリスト

    • さくらインターネット(株) 舘野 正明 さん
    • アマゾンデータサービスジャパン(株) 玉川 憲さん
    • 宮内宏法律事務所 宮内 宏さん
  • クラウドの利用が増えてきた

    • マーケットが成長してる
  • ここ5年でクラウドを取り巻く環境はどう変化したか
    • 玉川さん
      • awsは非常に大きく成長した
      • 東京リージョンが来てから営業しやすくなった
    • 舘野さん
      • 5年前は物理ベースだった
      • VPSが2010年
      • クラウドが2011年
      • 5年前は自社でサーバ作ってた
        • 昔はそのほうが安かった
        • 今はベンダーから買ったほうが安い
    • 宮内さん
      • エンドユーザーにとってはクラウドかどうかはもう関係ない
      • クラウド上のデータの責任はどうなのか
  • クラウドが盛り上がってきた背景
  • エンタープライズとコンシューマの境界線はどこか
    • awsもコンシューマからエンタープライズに向かって普及していった
    • amazonawsの客で、amazonのサーバはすべてaws
    • クラウドの安全性について(宮内さん)
      • 例えばアメリカにサーバがあるとpatriot actに...(聞き取れず)
        • 厳密にはそんなに心配ではないけれど
      • EUから日本にデータ持ってくるのは大変かも
        • EUデータ指令
      • 国内で普通に使っていて心配なのはデータが漏れるとか無くなるとか
        • ファーストサーバとか...
        • "ちゃんとやっている加減"をどう伝えるのか
    • データはデフォルト暗号化にしていくトレンドがある
      • awsはそもそも運用者が見れないような仕組み
      • httpからhttpsになっていくような流れと同じ
    • どこのサーバを利用するか場所を指定できる(舘野さん)
      • SaaSなら難しいけどIaaSならどの地域(国)に置かれているかわからないというリスクはない
  • クラウド時代のアイデンティティ
    • idの連携の役割の一つは認証の連携
      • データの連携もついてくる
    • 自分のデータがどう集約されるのか
    • USには帝国データバンクの個人版のようなものがある
      • こういうのが日本で出来たら怖い
    • 安易なID連携は危険
    • 想定していないID同士の紐付けは嫌ですよね
    • 企業買収によって思わぬIDの紐付きが行われる可能性もある
    • 国によってもかなり違う

総括 - 国立情報学研究所 中村 素典さん

  • 今年のキーワード(崎村さん)
    • Password is Dead
    • personal data
  • 次回は暖かい時期にやりたいですね

ac.jsを試してみました

結構前の話になりますが、OpenID TechNight Vol.9に参加した時にac.jsなるものがあると聞いたので、試してみました。

ac.jsとは

ac.jsとはaccount chooserを既存サイトに組み込むためのJavaScriptライブラリです。ac.jsを使用することで、account chooserのUXを既存のwebsiteに導入することができます。http://accountchooser.net から辿れるac.jsの解説ドキュメントにac.jsの簡単な導入方法があったり、少し細かい設定について書いてあるドキュメントもあるので、今回はそれらを参考に試しました。ちなみに、ac.jsはApache License 2.0です。

試す

今回は簡単なlegacy login(従来のemail, passwordなどを使ってログインする形式)を実装しました。

デフォルトでは以下のような構成のパスになります。パスはscriptタグ中に設定を記述することで変更することもできます。

名称 パス 用途
homeUrl / アプリのhome screen
loginUrl /account-login ログインページ
userStatusUrl /account-status ステータス確認エンドポイント
signupUrl /account-create アカウント作成ページ

動作の流れ

以下のような動作になります。

  1. ユーザーがWeb Pageにアクセスし、ログイン画面に遷移します。
  2. accountchooser.com上にアカウントが存在していると、ac.jsによりaccountchooser.comにリダイレクトが行われます。
  3. ユーザーがアカウントを選択します。
  4. ログイン画面に戻ります。
  5. ログイン画面からuserStatusUrlにPOSTでリクエストが行われます。
  6. userStatusUrlでは、Email(及びproviderId)を見て登録済みのユーザーであれば {"registered":true} を返し、未登録のユーザーであれば {"registered":false} を返します。
    • providerIdが指定されていたら {"registered":IP-Url} を返します。IP-UrlはIdPを利用してログインするためのURL。このパターンは今回は実装しません。
  7. ac.jsにより、{"registered":true} であればログイン画面に、{"registered":false} であればサインアップ画面にユーザーをリダイレクトさせます。
  8. loginUrlおよびsignupUrlでは従来通りのログイン・アカウント作成処理を行います。
  9. ログインが完了したら、ac.jsを含んだコンテンツを返します。
  10. ac.jsによりaccountchooser.comにリダイレクトが行われ、既にaccountchooser.comに存在しているアカウントであればhomeUrlにリダイレクトされ、存在していなければstoreするかどうかの確認がaccountchooser.comで行われます。確認後、homeUrlにリダイレクトされます。

実装

今回はデフォルトのパスで実装しました。それぞれのパスのhtml・JavaScriptは以下のようになります。 実際のサインアップ、ログイン処理は別途実装するか既存の実装を利用することになりますが、そのあたりは省略してます。 また、ac.jsは自動でinput fieldを埋めることもしてくれるのですが、対象となるinput fieldのidは各endpointのパスと同様に設定で変更可能です。

homeUrl

homeUrlのコンテンツはなんでも構いませんが、こんな感じで。ユーザーがログインしていなかったらloginUrlに飛ばす、もしくはloginUrlのリンクを貼ることになると思います。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>homeUrl</title>
    </head>
    <body>
        <h1>homeUrl</h1>
        <a href="/account-login">login</a>
    </body>
</html>

loginUrl

ac.jsを読み込むことと、formを設置する必要があります。formにはid=emailとid=passwordのinput fieldを設置します。accountchooser.comにアカウントが存在していない場合、リダイレクトが発生しないので、アカウント作成画面へのリンクでも貼っておきます(そのまま従来のログインをしても構いません)。ログインが成功したらアカウントの情報をscriptタグ内に記述することで、アカウントの情報をaccountchooser.comにstoreする処理が行われます。accountchooser.comにstoreした後はhomeUrlにリダイレクトされます。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>loginUrl</title>
        <script type="text/javascript" src="https://www.accountchooser.com/ac.js">
            storeAccount: {
                email: "foo@example.com",
                displayName: "bang_yy",
                photoUrl: "https://si0.twimg.com/profile_images/1146622182/___.png"
            }
        </script>
    </head>
    <body>
        <h1>loginUrl</h1>
        <form action="account-check" method="POST">
            <ul>
                <li>email: <input id="email" type="text" name="email"></li>
                <li>password: <input id="password" type="password" name="password"></li>
                <li><input id="submit" type="submit" value="submit"></li>
            </ul>
        </form>
        <a href="/account-create">create account</a>
    </body>
</html>

userStatusUrl

このエンドポイントはaccountchooser.comからPOSTされてくるユーザーのアカウント情報を見て、すでにアカウントが自サイトに存在していれば{"registered":true}を、存在していなければ{"regisitered":false}を、IdPにリダイレクトする場合は、{"registered":"IP-uri"}としてIdPを利用してログインするためのURLを返します。今回はlegacy loginなので最後のパターンはありません。

signupUrl

accountchooser.com経由で遷移してきたパターンだと、id=displayName, photoUrl, emailのinput fieldに自動でfillしてくれます。アカウント作成が成功したらアカウントの情報をscriptタグ内に記述します。このアカウントの情報をaccountchooser.comにstoreします。accountchooser.comにstore後はhomeUrlにリダイレクトされます。 また、loginUrlでaccountchooser.comにアカウントが存在していない場合はaccountchooser.comにリダイレクトがされないので、従来通りアカウント作成用の画面を表示する必要があります。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>signupUrl</title>
        <script type="text/javascript" src="https://www.accountchooser.com/ac.js">
            storeAccount: {
                email: "foo@example.com",
                displayName: "bang_yy",
                photoUrl: "https://si0.twimg.com/profile_images/1146622182/___.png"
            }
        </script>
    </head>
    <body>
        <h1>signupUrl</h1>
        <form method="POST">
            <ul>
                <li>displayName: <input id="displayName" type="text" name="displayName"></li>
                <li>photoUrl: <input id="photoUrl" type="text" name="photoUrl"></li>
                <li>email: <input id="email" type="text" name="email"></li>
                <li>password: <input id="password" type="password" name="password"></li>
                <li>confirm password: <input id="confirm" type="password" value="" name="confirm"></li>
                <li><input id="submit" type="submit" valur="submit"></li>
            </ul>
        </form>
    </body>
</html>

Identity Provider Filtering

今回は指定していませんが、Facebook loginなどを実装している場合は、以下のように記述することでサポートしているIdPのアカウントをaccountchooser.com上で表示させることができます。

<script>
    accountchooser.CONFIG.providers = ["yahoo.com", "facebook.com" ];
</script>

まとめ

今回のように、ac.jsを単純に組み込むだけだとそんなに良いUXにはなりませんが、ac.jsは他にもいろいろとできるのでもっとUXの良いフローの実装もできます。 あと、ac.jsでlegacy loginだけできてもあまり嬉しくないのでidPを使ったログインを実装したいところですが、ac.jsを使う場合のfederated loginではOAuthなりOpenID Connectなりの実装はRPがすることになります。

ac.jsはまだまだ変更がありそうな気がするので(実際、書いてる間にIdentity Provider Filteringの仕様が変わってました)、時折見ていこうかなと思います。

OAuth2.0対応サービスのstate, redirect_uriパラメータの扱い色々

この前行われたidconで、OAuth2対応サービスのstateパラメータとredirect_uriパラメータの扱いってどうなってる?という話題があったのと、以前途中まで調べたものがあったので、いい機会なのでまとめてみました。

stateパラメータとredirect_uriパラメータについて

まずstateパラメータとredirect_uriパラメータについてです。が、ちょうどstateパラメータとredirect_uriパラメータについて書かれたエントリがありましたので、そちらをどうぞ!

利用する側としては、もしstateパラメータが利用できなければredirect_uriにquery parameterでnonceなどを渡してstateパラメータの代わりにしたいところです。

調べたこと

今回はstateパラメータとredirect_uriパラメータの扱いについて、下記の5つのサービスを調べました。

Facebook

Facebookはstateパラメータが使用可能です。 redirect_uriに指定するURLは、下記の範囲内であればquery parameterを付加したりパスを変えたりできます。

https://developers.facebook.com/docs/authentication/server-side/

For security, the redirect_uri must have the same base domain as that specified in the App Domain property of your app's settings, or be a URL of the form https://apps.facebook.com/YOUR_APP_NAMESPACE.

mixi

mixiもstateパラメータをサポートしています。 mixiではredirect_uriは事前に登録する必要があり、また、authorization request時にredirect_uriを指定せず、登録したURLにリダイレクトするという仕様なので、リクエストごとに異なるquery parameterをつけるようなことはできません。

Google

Googleもstateパラメータは使用できることがちゃんとドキュメントに書いてあります。

https://developers.google.com/accounts/docs/OAuth2WebServer

Indicates the Google API access your application is requesting. The values passed in this parameter inform the consent page shown to the user. There is an inverse relationship between the number of permissions requested and the likelihood of obtaining user consent.

redirect_urlはauthorization request時に指定できますが、redirect_uriはclient idに対して登録されたものの内どれか1つにマッチするものでないといけません。

Instagram

stateパラメータ使えます。

http://instagram.com/developer/authentication/

Note: You may provide an optional state parameter to carry through any server-specific state you need to, for example, protect against CSRF issues.

redirect_uriは、query parameterが許されるパターンが明記されています。詳細に書いてあるというわけではないんですが、簡潔な説明で結構わかりやすいです。

foursquare

OAuth関連のドキュメントには書いていなかったのですが、試したところstateパラメータが使えました。 また、redirect_uriパラメータについては、これもドキュメントに書かれているわけではないですが、登録したredirect_uriにquery parameter加えてを指定することができました。(登録したredirect_uriの下位パスの指定を無視しているようです。前方一致?) 一応、チュートリアルにはstateパラメータを使ったサンプルがあったので、ドキュメントには使えるパラメータを明記しておいてほしいなーと思います。

まとめ

stateパラメータとredirect_uriパラメータの扱いは結構気になる部分だったのですが、個人的には意外とstateパラメータがサポートされているなーという感じでした。ありがたいですね。また、redirect_uriの扱いはサービスごとにかなり違うようです。

あ、stateパラメータが使える場合はちゃんとstateパラメータ使いましょう。redirect_uriでどうにかするのはあくまで次善の策だと思います。

参考

Facebookの認証ダイアログの仕様変更をまとめてみた

皆さんFacebook使ってますか?私はどちらかというとTwitterを使ってます。
下記のポストで説明されているのですが、Facebookが認証ダイアログの仕様を変えるようです。この変更が中々興味深い感じだったのでまとめてみます。
https://developers.facebook.com/blog/post/633/

変更点

今回の主な変更点は4つです。

1. ユーザーによるアプリのactivityの公開範囲設定

Facebookではウォールのポストごとに公開範囲を設定できますが、同じようにアプリがウォールにactivityを投稿する際の公開範囲を認証ダイアログで設定できるようになります。開発者がdeveloper appのDefault Activity Privacyでデフォルトの公開範囲を設定できるようにもなります。

2. アプリの説明エリアの追加

そのままなのですが、認証ダイアログにアプリの説明を行うためのエリアが追加されます。ユーザーにとっても開発者にとっても、アプリの説明が行えることはありがたいことですね。

3. Optionalなpermissionの表示

Extended permissionsを認証ダイアログの2つ目の画面で表示するようになります。この画面では、ユーザーに対して要求されているOptionalなpermissionを提示し、ユーザーはこれらのpermissionを拒否することもできるようになります。
また、developer appのExplanation for Permissionsの項目にpermissionを要求している理由を記入することができます。
あと、offline_access permissionがdeprecadeになります。あの、有効期限が設定されないaccess tokenのやつです。その代わりにaccess tokenを交換してexpireをresetすることが可能になるようです。

4. シームレスな認可手順の採用

この機能を有効にするとFacebook上でアプリのインストールを行う際にinlineでダイアログを表示することができるようです。

ユーザーによるpermissionの拒否について

3つめの変更が面白いですね。Facebookが定義しているpermissionはUser & Friend Permissionsと呼ばれるpermissionとExtended Permissionsと呼ばれるpermissionに大きく分類される(page用のpermissionもあったりはします)のですが、今回の認証ダイアログ変更でユーザーが拒否を行うことができるようになるpermissionはExtended Permissionsのみです。

実際に試すと以下のような感じになります。

まず、authZ endpointにリクエストします。今回はscopeにはuser_about_me(User & Friend Permissions)とread_friendlists(Extended Permissions)を指定してみます。

https://www.facebook.com/dialog/oauth?client_id=&redirect_uri=&scope=user_about_me,read_friendlists&response_type=code

認証ダイアログはこんな感じになっています
f:id:bang_yy:20120131003718p:image
インストールすると2つめの画面が表示されるので、
f:id:bang_yy:20120131003719p:image
右上の×ボタンでpermissionの拒否ができます。
f:id:bang_yy:20120131003720p:image
このあとGraph APIを使ってユーザーが許可しているpermissionを確認すると、

https://graph.facebook.com//permissions?access_token=

{
   "data": [
      {
         "installed": 1,
         "user_about_me": 1
      }
   ]
}

のように、ちゃんと拒否できていることがわかります。

開発者はaccess tokenを取得した時点ではユーザーが許可したpermissionを把握することができないので、Graph APIを使うなどしてユーザーに許可されたpermissionを確認する必要があります。ユーザーに許可されていないpermissionが必要な機能を選択された時点で"この機能を試すにはpermission: aを許可する必要があります"などと表示してauthZ endpointへのリンクを提示するようにするのがいいのでしょうか。

まとめ

ユーザーのコントロールできる範囲が広がり、良い方向で仕様変更が行われたように感じました。ついでと言っちゃ何ですが、この調子でaccess tokenとかをJSONで返すようにしてくれないですかね...

GeolocationAPI使ってみた

位置情報面白いですよね!
そんなわけで、GeolocationAPIを使ってみたのでまとめます。あまり難しいことを考えずに使う分にはすごい簡単でした。

GeolocationAPIとはなんぞや

まずGeolocationAPIて何ってことですが、specによると"各デバイスの実装により取得できる緯度経度のような位置情報を提供するインターフェースである"とありました。簡単に言ってしまうとjavascriptで"35.0000,135.0000"みたいな緯度経度の形式で現在地の情報を取得できるAPIのことです。

使ってみる

GeolocationAPIには

  • getCurrentPosition(現在地を取得する)
  • watchPosition(現在地を定期的に取得する)
  • clearWatch(現在地を定期的に取得するのをやめる。watchPositionに対応しています)

の3つのAPIがあります。今回はgetCurrentPositionのみの使用だったので、getCurrentPositionについてまとめます。調べただけですが、他の2つのAPIもかなり簡単に使えるようでした。
getCurrentPositionは以下のような仕様になっています。

void getCurrentPosition(successCallback[, errorCallback[, options]]);

successCallbackには現在地を取得できたときのコールバックを、同様にerrorCallbackには現在地を取得できなかったときのコールバックを指定します。optionsにはAPI呼び出し時のoptionを指定します。optionsは下記のようなオブジェクトを渡して指定します。

var options = {
    timeout: 10000,
    maximumAge: 20000,
    enableHighAccuracy: true
};

timeoutは現在地取得にかける時間(ミリ秒で指定)、maximumAgeはいつまでの位置情報のキャッシュを受け入れるかを指定します(ミリ秒で指定。0だとキャッシュの使用を許可しません)、enableHighAccuracyはアプリケーションに対して最も正確な位置情報を取得するように指定します(ただし、レスポンスが遅くなったりします)
あとは、GeolocationAPIを実装していないブラウザのために、

if (navigator.geolocation) {
    //GeolocationAPI使える!
} else {
    //GeolocationAPI使えない!
}

として機能テストしてあげます。
実際はこんな感じの実装になりました。

var options = {
    timeout: 10000,
    maximumAge: 20000,
    enableHighAccuracy: true
};

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
        function(position){
            var loc = position.coords.latitude + ',' + position.coords.longitude;
            alert(loc);
        },
        function() {
            alert('位置情報の取得に失敗しました');
        }, options);
} else {
    alert('お使いのブラウザではこの機能はサポートされていません');
}

まとめ

かんたんですね!スマホ用のWebアプリで定期的に現在地を取得したりすると面白いことができそうです。