Sign in with Apple 対応

# Sign in with Appleとは
Apple ID を利用したサインイン方法。
サードパーティーログインを使用しているアプリは2020/04までにSign in with Appleに対応する様に義務化した。
> App Storeに提出されるすべての新しいAppやアップデートは、2020年4月30日までにこれらのガイドラインに従う必要があります。
引用元：https://developer.apple.com/jp/news/?id=03042020d

そうです。いつものAppleの無茶振りです。
対応しないとリジェクトされてしまう為、仕方なく実装する事に、、
まずは仕様から

# アプリへの公開情報

アプリに公開される情報は大きく分けて以下の2つです。

* 名前
* メールアドレス
 * 公開メールアドレス
 * プライベートメールアドレス

これらの値はSign in with Apple新規登録時かユーザーがアプリと紐付け解除を行った後の初回のみ設定する事が出来ます。

#### 名前
アプリに連携する名前はアプリ毎にユーザーが設定することができます。
デフォルトではiCloud アカウントに設定している姓名が入ってきますが、公開したくない場合は任意の名前に変更可能になっています。

#### 公開メールアドレス

ユーザーがiCloudの登録に使用しているメールアドレス。
* 実際のメールアドレスなので転送を停止する機能などは今回対象外

#### プライベートメールアドレス

認証時にユーザーがメールアドレス（Apple ID）を非公開設定すると、Appleが自動生成したランダムな英数字のメールアドレスをアプリ（サービス）に連携する。その結果ユーザーは自身のメールアドレスを公開する事なくアプリでログインが可能になる。
* アプリとのメールやりとりはAppleが **アプリ→自動生成メールアドレス→プライベートメール** という形でメールを転送してくれる。(設定の必要あり)
* ユーザーはメールの転送を停止したり、転送先のメールアドレスを変更する事が出来る。

このプライベートメールアドレスは出来るとユーザーにとって何が嬉しいのか？
サービス登録時に実際のメールアドレスを使用するとサービスの利用を停止した後にもメールアドレスを保持されて悪用されるリスクがある。そこでこのプライベートメールアドレスを使用すると実際のメールアドレスはサービスに公開せず、利用停止したい場合には紐付け解除(プライベートメールアドレスの破棄)を行えば悪用されなくなるというメリットがある。

# アプリとの紐付けの解除

iCloudの管理画面からアプリとの紐付け解除を行うことが出来る。
ユーザーにとって

※iOS13以上では[設定>Apple ID(一番上の箇所)>パスワードとセキュリティ>Apple IDを使用中のApp]からでも解除出来る

# CSRF対策

Sign in with AppleはCSRF対策の為にAppleの認証APIを実行する際にstateを指定することができる。
簡単に言うとなりすまし防止の為にアプリで送信時に作成したstateとAppleの認証時に返されたstateが一致しているかを確認する。

完璧に仕様が分かったことで対応する事を以下に記載。

# 対応内容

あくまでアプリが対応する内容を記載する。

* コーディング
 * iOS13以上の対応
 * iOS12未満の対応(必須ではない)
 * Android対応(必須ではない)
* Apple Developerでの設定
 * Sign in with Appleの有効化
 * メールのホワイトリスト追加
 * ServiceIDの登録
* Xcodeの設定
 * Sign in with Apple有効化
* デザイン対応
 * ガイドラインに沿ったデザイン


# iOS13での対応

### Appleのログインボタンを生成する。

```LoginViewController.swift
    func setupProviderLoginView() {
        let authorizationButton = ASAuthorizationAppleIDButton()
        authorizationButton.addTarget(self, action: #selector(handleAuthorizationAppleIDButtonPress), for: .touchUpInside)
        self.loginProviderStackView.addArrangedSubview(authorizationButton)
    }
```

### ユーザーの姓名とメールアドレスを受け取る様な認証のリクエストをAppleに対して行う。

```LoginViewController.swift
    @objc
    func handleAuthorizationAppleIDButtonPress() {
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]
        
        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
    }
```
### Delegateで結果を受信する。

```LoginViewController.swift
extension LoginViewController: ASAuthorizationControllerDelegate {
    func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
        if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
            // 成功した場合　　　　　　　
            let userIdentifier = appleIDCredential.user
            let fullName = appleIDCredential.fullName
            let email = appleIDCredential.email
        }
    }
    
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // エラーが発生した場合
    }
}
```

# iOS12以下での対応

WebViewを利用して[Apple JS](https://developer.apple.com/documentation/signinwithapplejs)に対応する必要があります。
サーバサイドの実装が必要だったりAppleボタンを自作しなければならなかったりするので
出来ればiOS13以降のみの対応の方が無難だと思います。


# デザイン対応

Appleのガイドラインの記載を抜粋。
* Appleのボタンを目立つようにする
 * 他サードパーティのログインボタンよりも小さくしないこと
 * スクロールしないでもAppleのボタンが表示されるようにする
* ボタンの色は背景色と被らないようにする
などなど

ガイドラインに従わないとリジェクトされます。
実際に初めてSign in with Apple対応した時にはボタンと背景の色やフォントサイズなどでリジェクトされました。
（iOS12対応の為にボタンは自作しました）

https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/

# まとめ

iOS12以下に対応する為には、自作したボタンをAppleのデザインに合わせたり認証をWebViewで行ったりしないとならなく別対応が必要なので骨が折れますが、
iOS13のみなら基本Appleが提供しているSDKを使用すれば比較的簡単に開発が済みます。
最近（2020/03時点）リジェクトが厳しくなっている気がするのでデザインのガイドラインなどはしっかり読んで対応した方が良いです。

# 参考URL
*　サンプルコード
https://developer.apple.com/documentation/authenticationservices/adding_the_sign_in_with_apple_flow_to_your_app