CognitoでSign in with Appleを実装して当たった壁

# はじめに
2019年11月、Amazon CognitoがSign in with Apple[^1]をサポートしました。
[公式記事はこちら](https://aws.amazon.com/jp/about-aws/whats-new/2019/11/amazon-cognito-now-supports-sign-in-with-apple/)

触れる機会があったので、この記事では以下の事柄についてまとめてみました。

- Cognitoを利用して、Appleでサインインできるようになるまで
- Sign in with Appleの特徴
- 実際にぶち当たった壁

## 想定読者
- ★★★これからAppleのアカウント連携を利用して何かしたい人★★★
- OAuthとか認証認可なにそれ美味しいの状態の人
    - 筆者も依然勉強中のため、詳しすぎる人はちょっと御免です（アドバイスは歓迎します！）
- Vueにさくっと触れてみたい人（サンプルアプリあります！）

## お断り
Sign in…と言いつつ、この後日本語で「ログイン」や「ログアウト」という言葉が多数出てきます。

- Sign in=ログイン
- Sign out=ログアウト

と読み替えてください。

# Cognitoを利用して、Appleでログインできるようになるまで
いきなりですが、簡単にものづくりしましたので、説明します。
なお、この内容は、[AWSの公式ブログ(英語)](https://aws.amazon.com/jp/blogs/security/how-to-set-up-sign-in-with-apple-for-amazon-cognito/)や、[Classmethodさんの記事](https://dev.classmethod.jp/articles/cognito-support-siwa/)とかなり重複したため、一部省略があります。ご了承ください。
＃逆にこれらのドキュメントで設定できたので、信頼できるということです！

## ものづくり概要
3つの画面で構成されるウェブアプリです。
実際には色んなAPIが飛んでいるのですが気にしない。

- トップ画面
- Appleの認証情報を入れる画面（Appleが用意したページ）
- ログイン後の画面（ログインユーザの情報を取得して表示）

![overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/aa51d543-b0c8-8ec7-6370-e0a0a65049c5.png)


## 設定その１：Apple Developerでのアプリ登録および設定
⚠ Apple Developerに登録していない場合は、[こちら](https://developer.apple.com/jp/programs/how-it-works/)から登録してください。
なお、個人の場合は年額諭吉さん1枚以上かかります…頑張りましょう…

Apple Developerのページに進めたら、フッターから[証明書、ID、プロファイル（英語）](https://developer.apple.com/account/ios/certificate/)をクリックしてください。

### App IDの登録
左のバーをIdentifiers、右上のプルダウンをApp IDsにセットします。
新規に登録する場合は、＋マークをクリックして必要事項を入力します。
既存のアプリを編集する場合は、一覧から選択して必要事項を入力します。
![appid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/571d897a-6ba8-52d1-df26-70bcda2200cb.png)

Capabilitiesの一覧から、Sign In Appleを有効にすればOKです。
※ちなみに、Descriptionに記載する名称は、エンドユーザに表示されるアプリ名になります。
※ちなみに、Descriptionには英数字しか使えないという制約があります。
![appid-regist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/c8f12071-3e50-d25d-ab95-6948fc66a9f8.png)

### Service IDの登録
こちらもAppIDと同様の手順で＋マークから作成します。

Sign in with Apple関連の設定では、以下を記載します。

- Primary App ID: 前節で設定したApp IDを選択
- Domains: Cognitoのドメインを設定（後述）
- Return URLs: Cognitoのドメイン + `/oauth2/idpresponse`
![serviceID.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/06883f9f-2008-7e37-264a-e830611e39b3.png)

### Keyの登録と取得
認証用のキーを作成します。これも、左のバーにあるKeysから簡単に登録できます。
Editから登録したいApp IDを選択するようにしましょう。

![スクリーンショット 2020-03-31 18.25.46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/21189b3f-fbaf-33df-5f18-8f6b89dc92d6.jpeg)

作成すると、Key IDと鍵（.p8ファイル）がダウンロードできるので、ダウンロードしてください。
このページを離れると、ダウンロードはできませんので再生成が必要です。
![keyid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/25303f1f-8908-993c-d05b-5742b7278218.png)

## 設定その２：Cognitoへの登録
次に、Apple Developerで登録した設定値をCognitoに書き写します。

⚠ ユーザプールがすでに作成されている前提です。
わからない方でも[こちらの記事](https://blog.asial.co.jp/2018/09/21/3%E9%80%A3%E4%BC%91%E3%81%ABCognito_vue/aws-amplify%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E6%89%8B%E8%BB%BD%E3%81%AB%E8%AA%8D%E8%A8%BC%E6%A9%9F%E8%83%BD%E3%82%92%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3)や[AWSの公式ガイド](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-user-pool-as-user-directory.html)がかなりきっちりと書かれているので、トライしてみてください。

⚠ Apple側に設定するCognitoのドメインは、アプリクライアントの作成時に設定しています。
Amazon Cognitoドメインの方が作成が楽だったので、今回はこちらで作成しました。
![cognito-domain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/6d220729-3b33-d5ae-2b38-b0951bb58e9e.png)


さて、ユーザプールが作成できたら、左のバーからフェデレーション＞IDプロバイダーを選択します。
すると、Appleがあるので、ここまで設定した値を流し込んでいけばOKです。
![cognito.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/d467feac-8566-496b-673f-7d87a6b3fbaa.png)


| 項目名 |値  |
|---|---|---|
|AppleサービスID  |Service ID登録時に設定したIdentifier  |
|チームID  |Apple DeveloperのTeam ID（App IDの画面で表示されています） |
|キーID|Key登録後に表示されたKey ID|
|プライベートキー|.p8ファイルをそのままアップロードでOK|
|承認スコープ|任意（ここで設定した項目値をログインユーザからもらうことになります）|

ちなみに、今回はEメール、名前をアプリに表示させるので、共に取得する設定にしました。
有効化させればほぼ完成！

あとは、Cognitoユーザプールの属性と、Sign in with AppleでもらうEメール、名前を
属性マッピングの設定でマッピングすると完成です。

![スクリーンショット 2020-03-31 18.54.58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/b7f0a131-9468-11f8-1c88-c62e19ffe58d.jpeg)


## Webアプリの実装
お待たせしました。
Apple、Cognito双方の準備が出揃ったので、あとは概要にあるようなアプリを作って結びつけましょう。
・・・とはいうものの、ここはガッツリ省略します。
サンプルアプリをVueで実装してみたので、是非自分で環境を作ってお楽しみください。
https://github.com/taniyuu/sign-in-with-apple-sample

ちなみに、今回はaws-amplifyを使って、ログイン/ログアウトを実装しました。
以下は擬似コードですが、コアなところは数行で書けます。

```javascript
// User PoolのIDや、Cognitoドメインを設定したりする
import Auth from '@aws-amplify/auth'
Auth.configure(config)

// ログイン
Auth.federatedSignIn({provider: 'SignInWithApple'})

// ログアウト
Auth.signOut()
```


# Sign in with Appleの特徴
この章は、開発者というよりかは、1ユーザとして、このサービスの面白いところを上げていくコーナーです。
※[Apple公式](https://support.apple.com/ja-jp/HT210318)の受け売りみたいになってしまいました。

## Apple IDでアプリを管理できる
よく考えると、このようなサービスは山ほどあって、例えるなら
- AndroidユーザにとってのGoogleアカウントでログインして利用
- WindowsユーザにとってのOffice365アカウントでのログイン（企業向けではよくあると思います）
のiPhone、Macユーザ版に過ぎないです。（もちろん、WindowsでもApple ID自体は使えますが）

ただ、Apple IDをWebモバイルアプリに~~献上~~提供することで、ユーザ側でも管理できるようになりました。
https://appleid.apple.com/account/manage で「Apple IDを使用しているAppとWebサイト」
というところから、このようにSign in with AppleでログインしたWebモバイルアプリが一覧で見れるようになりました。

![website-manage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/5a937f5a-2768-4087-8f15-748dc0e6138f.png)

## Touch IDやFace IDが使える！
何よりもこれが操作性を向上させている感じがしました。ユーザ名とパスワード入力いらず。
基本的にはApple Payなどと同様な感覚で、認証させたいんでしょうね。
![mobile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/677383ea-e16b-cb22-2ca3-e5a7fd341c7e.png)


# 実際にぶち当たった壁
このようなエンドユーザにとっては願ったり叶ったり感のある機能ですが、開発者にとっては結構大変なようです。
Cognito×Appleのみで起こる事象もありました。

事実を記載することに注意しつつ、この章では、これから作ろうと思う人への注意点を書きたいと思います。

## 名前はアプリごとに好みに設定できる
こちらをご覧ください。
![change-name.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/490515cf-f256-d78c-07bf-7a6fb21060f1.png)


初期設定時に、元々の名前から変更するようなフォームがあります。
面白いと言えば面白いですが、エンタープライズ向けに管理するような類には向いてないかもです。

## 【Cognito特有？】姓名が逆転しており、姓名別に取得できない
先ほどのフォームでログインした後の画面です。
ここまで出来上がりの画面を見せなかったのはここで物申したかったからです。
![スクリーンショット 2020-03-31 16.55.52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416137/8801aed3-71a0-1e42-c1ed-87ec13b8d272.jpeg)

画面は「Welcome to Your Vue.js App」の下に、ユーザ名とアドレスを表示する仕様です。
ご覧の通り、ユーザ名の姓名が逆転しています（想定は「taniyuuです」）。
私の実装では姓名まとまった単位でしか取得できませんでした。

一部のネイティブアプリを実際に利用してみたときには、姓名分かれているアプリもあったので、この点は調査したり独自実装が必要かもしれません。[^2]



## メールアドレスが隠蔽できるので、アプリ or インフラ対応が必要
先の画像でお気づきかもしれませんが、メールアドレスの部分をあえてマスクしませんでした。
隠蔽できるというと聞こえが悪いかもしれませんが、Appleのプライベートアドレスというものを設定して登録に利用できます。
※ランダムに指定されるのでエンドユーザの好きな文字列にはできません。

この場合なにが起こるかというと、例えば登録者にメール配信する場合に、直接このEメールアドレスに送信しても、エラーになります。
アプリのドメインが正式ですよーというのを、Apple側に認識させなければなりません。[^3]

この課題に対応する手順には触れません(今回の記事の領域を大きく超える)が、以下の記事がトライしていたので参考になるかと思います。
https://notes.tret.jp/sign-in-with-apple-private-email-relay-service/


## 【Cognito特有】 Touch IDなどでアプリ名がnullになる

今回私の実装はWebアプリですが、iOSアプリでも利用できます。
ただその場合に顕在化した問題があるようです。[aws-amplifyのissue](https://github.com/aws-amplify/amplify-js/issues/4580)として挙げられています。
上記ページから抜粋したものですが、Touch ID、Face IDの場合にアプリ名がnullになってしまうようです。
![](https://user-images.githubusercontent.com/18604525/75526335-802f2400-5a09-11ea-9b60-cc71f6280067.jpeg)

## 【Cognito特有】【解決済】初回ログインでTouch IDなどを利用した場合、Eメールや名前が連携されない
実は[前掲のissue](https://github.com/aws-amplify/amplify-js/issues/4580)で、別の問題も議論されていました。
Cognitoの承認スコープでEメール、名前を設定したにも関わらず、Touch ID、Face IDでログインしようとした場合に、設定が出てこず、結果としてユーザプールにも連携されていないというバグがありました。
前の画像と比較すると一目瞭然かと思いますが、3月上旬に修正され、想定通りの挙動になりました。
![](https://user-images.githubusercontent.com/373633/71646948-96d42b80-2ca3-11ea-9484-6a96782106e5.png)


# まとめ
本記事では、CognitoからSign in with Appleを利用する手順から、実際に当たった壁について記載しました。

最後に言うのも何ですが、Appleのアプリでアカウント連携を実装しているものは、~~2020/4末~~ 2020/6末[^4]までにAppleのログインも実装せよという話があり、界隈ではザワザワしていた、というのを後になって知りました。[^5]

私はApple関連のサービスを使った実装をしてみたのは今回が初めてでしたが、実装の手軽さとTouch IDが使えるスマートさはピカイチでした。一方で、Googleなど他のID連携サービスと比べて独自路線を行っているのも事実であることから、Cognitoにおいても細かい問題が発生しているようです。

最初の想定読者に「★★★これからAppleのアカウント連携を利用して何かしたい人★★★」と書いたのはまさにここに帰着していて、「AppleのアプリはDeadlineに向けて頑張れ！」ですが、その他のWebアプリをはじめとする「ちょっと時間ある人」にとってのInput資料、Tipsになってもらえれば幸いです。


[^1]: 「Sign `I`n with Apple」と書いてあるページもたまに見かけるのですが、現在調べると小文字が正式のようです。
[^2]: 姓名が取れるようにも見える参考ガイド https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/configuring_your_webpage_for_sign_in_with_apple
[^3]: 「Private Email Relay Service」というAppleのサービスに対応することになります。その名の如く、実際のメールアドレスにリレーしてくれるサービスです。
[^4]: このご時世で延長されました。
[^5]: 参考 https://qiita.com/shiz/items/5e094910f742c2ad72a4