Sign in with Apple 連携メモ


* 既存アプリでSign in with Appleを導入する際の開発要素などをメモする。

## 大まかな処理の流れ

1. クライアントアプリは、Apple の認可要求エンドポイントで`Sign in with Apple`認証を行い、認可コードを取得する。
2. バックエンドアプリは、クライアントアプリから受け取った認可コードを受け取る。
3. バックエンドアプリは、認可コードとクライアントシークレットを指定してApple Tokenエンドポイントにリクエストし、IDトークンを発行する。
3. バックエンドアプリは、IDトークンを検証する。検証に成功した場合、ログイン成功とする。

※[シーケンス参考資料](https://www.slideshare.net/techblogyahoo/sign-in-with-apple-ios-idcon)



## 開発事前作業

* [公式](https://help.apple.com/developer-account/#/dev1c0e25352)を参考に、開発に必要な情報の登録/発行をApple Developersで行う。
  * `Service ID`の登録（認可要求リクエストの`clinet_id`に指定）
  * アプリドメインの登録（認可コードのリダイレクト先(`redirect_uri`)を指定）
  * `Key`の発行（トークンリクエスト時に指定する`client_secret`　JWT生成に利用）



## 開発要素

### Appleサインインボタンの配置

* [公式](https://developer.apple.com/documentation/signinwithapplejs/incorporating_sign_in_with_apple_into_other_platforms)からダウンロードする。
* [ガイドライン](https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/) に従って、サイズ、カラーをクエリパラメータで指定して利用する。



### 認可要求リクエスト (サインインページへのアクセス)

* `https://appleid.apple.com/auth/authorize`に以下のパラメータをクエリパラメータとして指定し、リクエストする。
  * 例：`https://appleid.apple.com/auth/authorize?client_id=[CLIENT_ID]&redirect_uri=[REDIRECT_URI]&response_type=[RESPONSE_TYPE]&scope=[SCOPES]&response_mode=[RESPONSE_MODE]&state=[STATE]`

**パラメータ**

| パラメータ名    | 必須/任意 | 説明                                                         |
| --------------- | --------- | ------------------------------------------------------------ |
| `client_id`     | 必須      | クライアント識別子                                           |
| `redirect_uri`  | 必須      | リダイレクトURI。ローカルホストやIPアドレス指定不可。        |
| `response_type` | 必須      | `code` 、 `id_token`から選択（両方指定も可能）。 `id_token` 指定の場合は、`response_mode` を `fragment` か `form_post`で指定する必要がある。 |
| `scope`         | 任意      | Appleから要求されたユーザー情報の範囲。 `name` か `email`。複数指定の場合は、スペース区切りをエンドコーディングして指定。例： `"scope=name%20email"`. |
| `response_mode` | 任意      | レスポンスの形式を指定。 `query`、 `fragment`、 `form_post`の中から指定する。 |
| `state`         | 任意      | ステート。CSRF対策用文字列。                                 |
| `nonce`         | 任意      | IDトークンとクライアントセッションを紐づけるための文字列。リプレイ攻撃対策用。 |



### Tokenエンドポイント リクエスト/レスポンス検証

#### リクエスト

* Apple トークンエンドポイントにリクエストし、アクセストークントークンの発行を行う。

  ```
  POST https://appleid.apple.com/auth/token
  ```

**パラメータ**

| パラメータ名    | 必須/任意 | 説明                                                         |
| --------------- | --------- | ------------------------------------------------------------ |
| `client_id`     | 必須      | クライアント識別子。                                         |
| `client_secret` | 必須      | Apple Developers で生成した鍵を使用し、生成したJWT。         |
| `code`          | 必須      | 認可コード。認可コード検証時は指定。                         |
| `grant_type`    |           | `authorization_code`を指定。リフレッシュトークン検証時は`refresh_token`を指定。 |
| `redirect_uri`  |           | リダイレクトURI。認可要求リクエスト時に指定した値。          |

#### レスポンス検証

* レスポンス

| パラメータ      | 説明                                                 |
| --------------- | ---------------------------------------------------- |
| `access_token`  | アクセストークン。リソースアクセスに利用。           |
| `expires_in`    | アクセストークン有効期限。秒。                       |
| `id_token`      | IDトークン。ユーザー情報のJWT。                      |
| `refresh_token` | リフレッシュトークン。アクセストークン再発行に利用。 |
| `token_type`    | アクセストークン種別。`bearer`                       |

* IDトークンの検証
  * [公式](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple)のIDトークン構成に従い、IDトークンの中身が期待通りの値か検証する。
    * IDトークン署名の検証には、公開鍵取得が必要。



## 参考情報

* [Incorporating Sign in with Apple into Other Platforms](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/incorporating_sign_in_with_apple_into_other_platforms)
* [Sign in with Appleをサーバーサイドで実装した](https://qiita.com/meSummery/items/195b59adc7783d8635d8)