AndroidでQiitaのOAuth認証をしてみる


##はじめに
今更感がありますが、勉強も兼ねてAndroidのQiitaクライアントを作ってみたいと思います。
Qiitaクライアントを作成するためには当然QiitaのREST APIを実行する必要があります。
QiitaのREST APIを実行するには、一部を除いてアクセストークンをHTTPリクエストに含める必要があります。
アクセストークンを取得するにはOAuth認証を通す必要がありますので、まずはそこからやっていきたいと思います。

##1. OAuth認証方法を決める
まず思い浮かんだのが、 **「WebViewを配置し、Qiitaの認証ページを直接表示して認証する」** だったのですが、
調べてみるとどうやらこのやり方、セキュリティ的にあまりよろしくないらしいです。

参考：
[OAuthの認証にWebViewを使うのはやめよう](https://shogo82148.github.io/blog/2012/11/24/no-more-webview/)

ということで今回は、WebView上ではなくブラウザ上でユーザーに認証してもらい、
認証後に自アプリに遷移するように実装していくことにしました。

##2. Qiita上でアプリケーションを登録する
1. ブラウザからQiitaにログイン
2. [設定] -> [アプリケーション] -> [アプリケーションを登録する] を選択
3. アプリケーションの名前、アプリケーションの説明、WebサイトのURLを適当に入力。
4. リダイレクト先のURLに「 **[任意のスキーマ名]://callback** 」 と入力
5. [保存]を選択

リダイレクト先のURLには、認証が終わった後に自動でリダイレクトされるURLを指定するのですが、
Androidのネイティブアプリで何指定するの？？というのが最初謎でした。
他のアプリとかぶらない独自スキーマでURLを書いておき、自作アプリで受信するように
AndroidManifestのintent-filteに記載してあげれば自作アプリにリダイレクトしてもらえるようです。
何でもいいのですが、今回は「 **qiitaviewer://callback** 」としておきます。

保存を選択すると、 **Client ID**  と  **Client Secret** が入力されるのでメモしておきましょう。
OAuth認証時とアクセストークンを取得する際に使用します。


##3. 認証後のリダイレクトで自作アプリが表示されるよう設定
以下のように、intent-filterに独自スキーマを定義し、Qiita上でリダイレクト先のURLに指定したURLを処理できるようにします。

```xml:AndroidManifest.xml
        <activity
            android:name=".ui.Activity.MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="callback"
                    android:scheme="qiitaviewer" />
            </intent-filter>
        </activity>
```

##4. ブラウザで認証画面を開くIntentを投げる
以下のようなコードを記載してQiita APIを実行するIntentを作成します。

* アプリケーション登録時にメモしておいた **Client ID** を **client_id** に設定
* **"read_qiita"** を **scope**に設定。設定可能な値は参考URLで詳しく解説してあります。
* 任意の16進文字列を **state** に設定。こちらも参考URLで詳しく解説してあります。

参考：
[Qiita API v2ドキュメント](https://qiita.com/api/v2/docs#get-apiv2oauthauthorize)
[[Qiita] QiitaにおけるOAuth認証の流れ（PhoneGap/Cordova版）](https://qiita.com/nutti/items/688de20382e60286d26d)

```java:AuthorizationManager.java
    public Intent requestLoginIntent() {
        String uri = "https://qiita.com/api/v2/oauth/authorize?" +
                "client_id=" + mClientId +
                "&scope=" + mScope +
                "&state=" + mState;

        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
        return intent;
    }
```

今回は、OptionMenuからログインメニューを押下したタイミングで、
以下のようにして上記メソッドを呼び出し、ブラウザで認証画面を開くIntentを投げるようにしました。

```java:MainActivity.java
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

       int id = item.getItemId();
       if (id == R.id.action_login) {
            Intent intent = mApplication.getAuthManager().requestLoginIntent();
            startActivity(intent);
        }

        return super.onOptionsItemSelected(item);
    }
```

これで、ブラウザでQiitaの認証画面が開き、認証が終わると自作アプリが再度表示されるようになりました。

##おわりに
これでOAuth認証を通すことができました。
Qiitaに限らず、AndroidアプリからOAuth認証する場合似たような流れになるのではないかと思います。
もしもっと良い方法があれば是非教えてくださると助かります。

次は、他のQiita APIを実行する際に必要なアクセストークンを取得する流れをやっていこうかと。

##参考情報
* [Qiita API v2仕様](https://qiita.com/api/v2/docs)