HMS Account Kit実装入門（Authorization Code編）

# 前書き
[HMS Account Kit実装入門](https://qiita.com/Rei_2020/items/81001ffc6299e56401c8)でIDトークンによるユーザー認証を紹介しました。本章はAuthorization Codeによるユーザー認証と、IDトークンによるユーザー認証との違いを紹介したいと思います。

# 前準備
AppGallery ConnectでAccount Kitの設定ページに入り、redirect_uriをセットします。サーバー側がユーザー情報をファーウェイのアカウントサーバーから取得する場合は設定しなければなりません（APIを呼び出すのに必須なパラメータであるため）。
<img width="300" alt="スクリーンショット 2020-10-01 233255" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/db817e4a-a3f3-5b6b-bf41-25e3b8322b30.png">

# 実装

こちらはオフィシャルサイトに掲載されているシーケンス図です。
<img width="600" alt="accountKitClientIdToken.png" src="https://communityfile-drcn.op.hicloud.com/FileServer/getFile/cmtyPub/011/111/111/0000000000011111111.20200930110613.52904963380230098269179032460105:50510930061339:2800:EA5C651C3260316F32CB8C763364E2B315075FA14259B8A6D6FBF4555D0CACB7.png">

各ステップに対応しているコード実装は下記に示します。

### ステップ１
ユーザーが”HUAWEI IDでログイン”ボタンを押すというプロセスです。ボタンのデザインは細かく定められているので、オフィシャルページをご参照ください。
[HUAWEI ID Sign-In Icon Specifications](https://developer.huawei.com/consumer/jp/doc/HMSCore-Guides-V5/dev-specifications-0000001050048916-V5)

### ステップ２～４
”HUAWEI IDでログイン”ボタンが押されたときの処理です。

```kotlin:MyActivity.kt
private var authManager: HuaweiIdAuthService? = null

private fun signInAuthorizationCode() {
	val param = HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
		.setAuthorizationCode()
		.createParams()
	authManager = HuaweiIdAuthManager.getService(activity, param)
	authManager?.let {
		startActivityForResult(it.signInIntent, REQUEST_CODE_SIGN_IN_AUTHORIZATION_CODE)
	}
}
```

### ステップ５～６
HMS Account Kitの内部の認証済み確認処理とユーザーが明示的に認証を承認するプロセスです。こちらはコード実装不要です。

### ステップ７～９
Authorization Codeとユーザーのアカウント情報はここで返ってきます。

```kotlin:MyActivity.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
	super.onActivityResult(requestCode, resultCode, data)

	when (requestCode) {
		REQUEST_CODE_SIGN_IN_AUTHORIZATION_CODE -> {
			val authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data)
			if (authHuaweiIdTask.isSuccessful) {
				// Authorization Code= authHuaweiIdTask.result.authorizationCode
				// ユーザー名 = authHuaweiIdTask.result.displayName
				// ユーザーのアバター画像のURL = authHuaweiIdTask.result.avatarUri
				// ユーザーのメールアドレス = authHuaweiIdTask.result.email
			}
		}
	}
}
```

### ステップ１０
サーバーにユーザー情報を渡すときにのみ必要です。

### ステップ１１～１２
サーバーがユーザー情報をファーウェイのアカウントサーバーから取得する場合のみ実装が必要です。

ここでは２ステップがあります。

<b>Authorization CodeによるIDトークンの取得</b>
API（開発者）：https://oauth-login.cloud.huawei.com/oauth2/v3/token
API（運営側）：https://oauth-login-at.cloud.huawei.com/oauth2/v3/token
メソッド：POST
リクエストのパラメータ：

|キー|値|
|:---:|:---|
|grant_type|"authorization_code"で固定|
|client_id|AppGallery ConnectのMy AppsのApp informationのApp ID|
|client_secret|AppGallery ConnectのMy AppsのApp informationのApp secret|
|code|Authorization code|
|redirect_uri|AppGallery ConnectにセットしたリダイレクトURI|

レスポンスはJSONとなります。IDトークンはid_tokenに入っています。

詳細はこちらをご参照ください。
[Obtaining an Access Token](https://developer.huawei.com/consumer/jp/doc/HMSCore-References-V5/account-obtain-token_hms_reference-0000001050048618-V5)

![スクリーンショット 2020-10-01 234024.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/94388796-8118-a2f3-0ba5-d7a39f07747c.png)

<b>IDトークンの解凍</b>
IDトークンを解凍すれば、ゆーざー情報が得られます。解凍方法について、[HMS Account Kit実装入門](https://qiita.com/Rei_2020/items/81001ffc6299e56401c8)の”IDトークンの有効性検証”と”IDトークンの有効性検証とは？”をご参照ください。

# Authorization Code認証とIDトークン認証の違い
### Android観点
Androidの実装に焦点を当てれば、Authorization Code認証とIDトークン認証に違いがありません。行っていることが同じです。

### サーバー観点
Authorization Code認証はIDトークン認証より１ステップが多いです。
Authorization Code認証では、まずAPIを通して、Authorization CodeをIDトークンに変えなければなりません。それ以降の処理はIDトークン認証と同じです。

# セキュリティについて
そもそもIDトークン自体にユーザー情報が入っているので、暗号化したからとはいえ、IDトークンをクライアントからサーバーに渡すということ自体には当然それなりのリスクがあります。それと比べて、Authorization Codeの場合、Authorization Codeだけでは何の意味もなさないので、IDトークンの受け渡しよりセキュリティ的により安全と言えます。

# 最後
Authorization Code認証もIDトークン認証もどちらもよい部分があるので、フロントエンドとバックエンドを含めた全システムのアーキテクチャを考えて、最適なものを選べばよいでしょう。

# 参考
* オフィシャルのデモ：[https://github.com/HMS-Core/huawei-account-demo](https://github.com/HMS-Core/huawei-account-demo)