kurukuru-papaのブログ

主に、ソフトウェア開発に関連したメモを書き溜めたいと思います。

AndroidでOAuth認証をしたい

タイトルのまんまなのですが、Androidで、OAuth2.0認証をしたくなったので、調べてみました。なかなか理解できませんでしたが、何とか実装することができました。自分が理解したことをまとめてみたいと思います。
なお、私は、WebアプリケーションでOAuth1.0認証を行った経験はありましたので、OAuthの概要については、理解しているつもりでした。

難しかったところ

簡単に沢山の情報が見つかり、それぞれ分かりやすく具体的に書かれていましたが、どれも実装方法が異なり、どの実装方法を参考にすれば良いか、わかりませんでした。
実装方法が異なるのは、アプリケーションの形態や、ユーザーへの見せ方、使用ライブラリなどが異なるためでした。

実装パターン一覧

調べてみた実装方法について、自分なりに解釈した内容を表にまとめてみました。今回は、Androidアプリの実装方法に注目していますが、比較のため、Webアプリケーションとコンソールアプリケーションも記述しています。私がざっと調べて見つけた実装方法のみ記述していますので、探せば他にも色々あると思います。

パターン番号 アプリケーション形態 接続先 認証画面UI ライブラリ ユーザ操作
1 Androidアプリ Webサービス(コールバック) WebView 未使用 or 各種ライブラリ ID・パスワード入力
2 ブラウザアプリ
3 Webサービス(OOB) ブラウザアプリ ID・パスワード入力。PINのコピー&ペースト。
4 Googleサービス ブラウザアプリ Google APIs Client Library for Java ※1,2 ID選択。パスワード不要。
5 Googleサービスのみ? Android OS Android SDK (AccountManager) ID選択。パスワード不要。
6 Webアプリケーション Webサービス(コールバック) ブラウザ 未使用 or 各種ライブラリ ※2 ID・パスワード入力
7 コンソールアプリケーション Webサービス(OOB) ブラウザ ID・パスワード入力。PINのコピー&ペースト

※1 「Google APIs Client Library for Java」と同様のライブラリとして「Google Data Java Client Library(gdata-java-client)」というものもありました。「Google Data Java Client Library(gdata-java-client)」は、2012年3月頃で開発が止まっているようで、「Google APIs Client Library for Java」の前世代のライブラリのようでした。

※2 「Google APIs Client Library for Java」は、Androidアプリでも、Webアプリケーションでも使えます。たぶん、コンソールアプリケーションでも使えると思います。使う場合は、Androidアプリの場合、GoogleAccountCredentialクラス、GoogleAuthUtilクラスを使います(GoogleAccountCredentialクラスは内部でGoogleAuthUtilクラスを使用)。Webアプリケーションの場合、GoogleAuthorizationCodeFlowクラスを使います。

Androidアプリにおける実装パターン1~5について、画面イメージは次のようになります。

実装パターン1

アプリケーション形態:Androidアプリ
接続先:各Webサービス(コールバック)
認証画面UI:WebView
ライブラリ:未使用、各種ライブラリ使用のいずれでも実装可能
ユーザ操作:ID・パスワード入力

自作アプリです。OAuth認証を行うきっかけを用意しておきます。ここでは、開始ボタンを用意しました。
https://qiita-image-store.s3.amazonaws.com/0/24511/b51f0e00-4cb4-95c3-3383-09a63c228be1.png

自作アプリの内部に、WebViewを使用して、各Webサービスの認証画面を表示します。ここでは、Twitterの認証画面を表示しています。認証画面を表示する時には、コールバックURLを設定します。コールバックURLは、認証完了後に呼ばれるURLで、自作アプリ用のURLを設定しておきます。ユーザは、アカウントのIDとパスワードを入力し、アクセス権限を確認します。
https://qiita-image-store.s3.amazonaws.com/0/24511/dceb44bb-2612-fe93-512b-37ce918a38fc.png

認証後、自作アプリから、各Webサービスの情報にアクセスできるようになります。ここでは、アカウント情報を取得し、画面表示してみました。
https://qiita-image-store.s3.amazonaws.com/0/24511/e618b935-f02c-75d1-c49d-5dcb60fcddba.png

この実装パターンは、Androidアプリでもよく見かける気がしますし、Webアプリケーションにおいても同じ流れになりますので、ユーザーにとっては、慣れている操作手順かもかもしれません。

ただし、セキュリティ的な危険性を指摘するブログなどを見かけました。悪意ある開発者であれば、自作アプリ内のブラウザで入力されたアカウントのIDとパスワードを盗み取ってしまえるらしいです。ですが、個人的には、自作アプリなり、開発チームや会社などが、ユーザから既に信頼を得られているのであれば、この方式でも概ね受け入れられている気がします。

実装パターン2

アプリケーション形態:Androidアプリ
接続先:各Webサービス(コールバック)
認証画面UI:ブラウザアプリ
ライブラリ:未使用、各種ライブラリ使用のいずれでも実装可能
ユーザ操作:ID・パスワード入力

基本的には、実装パターン1と同じですが、WebViewの替わりに、Android端末内にインストールされているブラウザアプリを呼び出す方式です。

自作アプリです。開始ボタンをタップするとブラウザアプリを起動します。
https://qiita-image-store.s3.amazonaws.com/0/24511/ffed62ff-172b-fcf3-b24c-5130846b3f9f.png

端末内に複数のブラウザアプリがインストールされ、デフォルトが決められていない場合、ブラウザアプリを選択するダイアログが出ます。認証完了後に自作アプリが呼ばれるように実装しておきます。
https://qiita-image-store.s3.amazonaws.com/0/24511/bb2c3b0e-df4d-aa1a-3af2-d4560908ac61.png https://qiita-image-store.s3.amazonaws.com/0/24511/280f0bb1-ea3e-7d1e-8dd5-9353e5f14718.png

認証後、各Webサービスの情報にアクセスできます。
https://qiita-image-store.s3.amazonaws.com/0/24511/67bd2fe9-6839-90f9-97b6-4ac2e758435b.png

この実装パターンは、WebViewを使った時と比べて、セキュリティ面が改善されています。ブラウザアプリに入力されたアカウントのIDとパスワードを盗み取ることが困難なためです。

実装パターン3

アプリケーション形態:Androidアプリ
接続先:各Webサービス(OOB)
認証画面UI:ブラウザアプリ
ライブラリ:未使用、各種ライブラリ使用のいずれでも実装可能
ユーザ操作:ID・パスワード入力と、PINのコピー&ペースト

実装パターン2と比較して、各Webサービスの画面から、自作アプリへの戻り方が異なります。

自作アプリです。ここでは、連携確認ボタンをタップするとブラウザが起動するようにしました。
https://qiita-image-store.s3.amazonaws.com/0/24511/3c397072-7079-6546-e9df-4864b87382b9.png

Webサービスで認証後、PINと呼ばれるコードが払い出されます。ユーザにPINをコピーしてもらい、自作アプリへ戻ってもらいます。
https://qiita-image-store.s3.amazonaws.com/0/24511/d41e1289-a421-752b-04cc-f8acd9a65c43.png https://qiita-image-store.s3.amazonaws.com/0/24511/cdb0f83d-62e3-e9f0-bb22-b9f89ebf6400.png https://qiita-image-store.s3.amazonaws.com/0/24511/4aa5149a-db65-aaef-88d6-b5f08245264c.png

自作アプリに先ほどのPINを貼り付けてもらいます。このPINを使って、各Webサービスに接続し、情報にアクセスできるようになります。
https://qiita-image-store.s3.amazonaws.com/0/24511/6550e54c-81bb-6f74-78ee-5aa13765fe74.png https://qiita-image-store.s3.amazonaws.com/0/24511/61c36ee9-b360-0600-2532-735027e56bf4.png

PINを使うことで、各Webサービスと自作アプリの連携が少なくなりますので、セキュリティ面が安全になるようです。ただし、ユーザの操作性が悪くなるため、個人的にはあまり使いたくない実装パターンだと思います。

なお、ブラウザアプリの替わりに、WebViewを使用して実装することもできます。しかしながら、PINを使うことのセキュリティ面のメリットが失われてしまいますので、あまり意味がないと思います。

実装パターン4

アプリケーション形態:Androidアプリ
接続先:Googleサービス
認証画面UI:ブラウザアプリ
ライブラリ:Google APIs Client Library for Java 使用
ユーザ操作:ID選択。パスワード不要。

実装パターン4は、今まで説明した実装パターンとは、だいぶ異なります。
この実装パターンが使えるのは、Android端末で、Googleアカウントのみです。

自作アプリです。
https://qiita-image-store.s3.amazonaws.com/0/24511/2ac1b499-0c11-5441-abb1-ecf15bb52604.png

まず、認証に使用するGoogleアカウントを決定します。ここでは、Android SDKのAccountManagerを使用し、Androidの機能を呼び出して、端末に登録されているGoogleアカウントから、今回使用するアカウントを選択してもらいました。新規にGoogleアカウントを端末に追加して、使用することもできるようです。Googleアカウントを選択するだけで、パスワードの入力は不要です。(なぜ、パスワードがいらないのだろう?あまり理解できていないです。)
https://qiita-image-store.s3.amazonaws.com/0/24511/36bb592c-5bbe-d3f1-70e8-b29766dae4bc.png https://qiita-image-store.s3.amazonaws.com/0/24511/d2fc224f-6f64-e14d-6312-8760550415f4.png

認証後、Googleサービスの情報にアクセスできます。
https://qiita-image-store.s3.amazonaws.com/0/24511/0fbcddc0-ce76-b9fe-dd4f-f98199babfb5.png

この実装パターンでは、ユーザ操作がかなり簡単ですね。文字を入力することがなく、数回タップするだけです。
ただし、セキュリティ面はどうでしょう?端末を紛失して、悪意ある人に使われてしまうと、勝手に認証操作を行われてしまいそうです。とはいえ、端末を奪われた時点で、もっと大きな問題が発生するでしょうから、他者に操作される懸念は別の観点で考えたほうがよいのではないでしょうか。

実装パターン5

アプリケーション形態:Androidアプリ
接続先:Googleサービスのみ?
認証画面UI:Android OS
ライブラリ:Android SDKのAccountManager使用
ユーザ操作:ID選択。パスワード不要。

実装パターン5は、ユーザにとって、実装パターン4と似たように見えるかもしれませんが、実装は別物です。認証情報が管理される場所も異なります。実装パターン1~4では、各Webサービスのサーバ側で認証情報が管理され、各WebサービスがWeb上で提供しているアカウント管理画面から認証を解除することができました。しかし、実装パターン5では、Android端末側で管理されるようです。Web上のアカウント管理画面を見ても、自作アプリとアカウントが紐づいていることが分からない状態となっていました。どうしたら認証状態を確認できるのか、どうしたら解除できるのか、わかりませんでした。

自作アプリです。
https://qiita-image-store.s3.amazonaws.com/0/24511/38e9d8c4-8740-8ea9-650e-7bdab22aab25.png

AccountManagerが、必要に応じて、Account選択ダイアログを出したり、認証ダイアログを表示してくれます。Googleアカウントを選択するだけで、パスワードの入力は不要です。
https://qiita-image-store.s3.amazonaws.com/0/24511/f5ae6251-d997-c562-366b-401aa82d4c41.png https://qiita-image-store.s3.amazonaws.com/0/24511/3ab1dea8-0ae4-3523-e0f6-11d88a183d25.png

認証後、Googleサービスの情報にアクセスできます。
https://qiita-image-store.s3.amazonaws.com/0/24511/691df30f-b3a8-91ab-35f0-6760bc887f2e.png

この実装パターンでも、実装パターン4と同様に、ユーザ操作がかなり簡単ですね。文字を入力することがなく、数回タップするだけです。

セキュリティ面では、実装パターン4と同じ問題がありまそうです。Androidが進化を続けても、この実装パターンは、使い続けられるのでしょうか?よくわかりません。私の理解不足が多分にあるため、どう扱うべきか決めかねています。

まとめ

以上のように、AndroidアプリにおけるOAuth認証の実装方式は、すくなくとも5パターンありました。しかも、探せばもっと他の実装パターンもあるかもしれません。Webアプリケーションでは、概ね1パターンであったのと比べるとかなり違いますね。

説明した実装パターンについて、比較してみます。

パターン番号 適用範囲 操作性 セキュリティ
1
2
3
4
5

Googleサービスのみを使う場合は、実装パターン4で実装すると、使い勝手がよさそうです。実装パターン5も同様ですが、私があまり理解できていないので選択肢から外しています。Googleサービス以外のサービスを使う場合は、実装パターン2がよさそうです。

以上、ひとまず自分の理解をまとめてみました。もし、誤りなどありましたら、コメント頂けるとありがたいです。

動作確認

確認環境

確認用プログラム

変更履歴

2014/11/21 実装パターン5(AccountManager使用)を追加しました。