
こんにちは、バックエンドエンジニアのキダです。
先日くらしのマーケットでSign In With Apple(SIWA)対応のリリースをしました!
SIWA対応でハマった点などを紹介いたしますので、興味がある方は参考にしてください。
背景
AppleのポリシーによりApple IDでログインできるソーシャルログイン機能のSign In With Apple(SIWA)は2020年7月より対応必須となりました。
※ 元々は2020年4月からとなっていましたが、コロナウィルスの影響もあり延期されていました
対応必須の詳細は以下になります。
- ソーシャルログイン機能持つアプリはSIWAの対応が必要
- 対応してない場合、Appleのアプリの審査が通らない(新しいバージョンのアプリをリリースできない)
くらしのマーケットは店舗向けアプリと、ユーザー向けアプリが存在します。
ユーザー向けアプリは『Yahooログイン』『LINEログイン』を対応しているので、SIWAの対応が必須になっていました。
ユーザー向けアプリはAndroid、iOS共にWebViewで作成されていて、アプリネイティブの機能以外は全てWeb側で実装されています。その為それほど優先度は上がっていなかったのですが、iOSユーザー向けアプリにマージ済みでリリースできていない機能が溜まってきた為、2021年1月より対応を進めていました。
SIWAの特殊なところ
さて、そろそろ本題に入ります。
SIWAが他のソーシャルログイン機能と比較して異なる点を箇条書きにしてみます。
- iOS端末(mac, iPhone)のSafariでは独自のサインインUIが利用可能で端末にログイン済みのApple IDで簡単にSIWAでの認証が可能(
touch ID
, face ID
利用可)
- メールアドレス、ユーザー名を連携するためにはコールバックエンドポイントをPOSTで実装する必要がある
- 利用者はメールアドレスの匿名化オプションと、転送停止設定が可能
1.はとても便利な機能なのですが、2,3は開発する際に考慮する必要があり、主にこの点でハマったので詳細を説明します。
この点はdev.toの記事がとても参考になったので、合わせて確認いただけるとよいと思います。
なおAppleのデータ、デザインに関するガイドラインは以下になるので、こちらもご一読する事をお勧めします。
https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/data-management/
https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/buttons/
メールアドレス、ユーザー名を連携するためにはコールバックエンドポイントをPOSTで実装する必要がある
例えばYahooやLINEログインは以下のようなフローで Authorization Code
のOAtuh2認証がされています。
- ログインボタンをログインや会員登録やアカウント連携ページに配置(/login, /regist, /connect のようなURL)
- ボタンを押すと、それぞれのソーシャルアカウントでの認証処理を実行
- 認証完了後に、元のページに code, state のパラメータをクエリストリングに付与してリダイレクト
- 元ページではcodeの内容を検証して、問題なければ認証完了として、ログインや会員登録が完了
ここの3でのリダイレクト処理はGETでリクエストされます。
さて、SIWAではどうなっているでしょうか。
まずSIWAでの1のボタンに設定するURLは以下のように設定可能です。
https://appleid.apple.com/auth/authorize?response_type=code&scope=email&response_mode=form_post&client_id={{ clientId }}&redirect_uri={{ redirectUrl }}&state={{ state }}&nonce={{ csrfToken }}
それぞれパラメータは以下のようになります。
パラメータ |
用途 |
設定例 |
response_type |
Authorizationフロー |
code(id_tokenも可) |
scope |
連携するユーザー情報 |
emailとname |
response_mode |
リダイレクト方法 |
form_post, query, fragment |
client_id |
Appleで登録する識別子 |
|
redirect_uri |
リダイレクトURL |
https://example.com/login |
state |
リダイレクト先で検証可能なcsrfTokenなど |
自由に設定可能 |
nonce |
リダイレクト先で検証可能なcsrfTokenなど |
自由に設定可能 |
ユーザー情報を連携するためにはresponse_mode
をform_post
に指定する必要があり、GETで戻す前提の作りになっていたため、リダイレクト先でPOSTを受け取れるように修正する必要がありました。
くらしのマーケットでは先の/login, /regist, /connectのようなページは元々GET,POST存在していましたが、既存の仕組みではcsrfTokenのチェックでリダイレクト時にエラーが出てしまいました。
■ 対応策
こちらの問題の対応として、Appleからリダイレクトする専用のエンドポイントを作って対応しました。
以下のようなredirect_uri
を設定して、動作します。
https://example.com/redirect/?/login
- ログインボタンをログインや会員登録やアカウント連携ページに配置(/login, /regist, /connect のようなURL)
- ボタンを押すと、それぞれのソーシャルアカウントでの認証処理を実行
- 認証完了後に、/redirectページに code, stateのパラメータをクエリストリングに付与してリダイレクト
- /redirectページで、stateの値を用いてセッションに保持したcsrfTokenチェックをして、問題無ければ元ページにGETでリダイレクト
- 元ページではcodeの内容を検証して、問題なければ認証完了として、ログインや会員登録が完了
/redirectを挟む事で元のエンドポイントでの修正を抑えて実装することが可能でした。
これにて一件落着に見えたのですが、もう一つPOSTに起因する問題がありました。
samesite cookieの対応
Google Chromeではこの認証フロー中にapple側の認証前(1.の状態)、apple認証後(4.の状態)でセッションが変わってしまう問題が出る事に気付きました。
具体的にどういうことかというと、セッション情報はcookieに保持していて、長期間同一のセッションとして管理されています。
Google Chromeでは2020年ごろからデフォルトのcookieプロパティがLaxになっており、今回POSTでリダイレクトする際にこのセッション情報を管理するcookieが失われてしまうといった問題が出ました。
こちらの問題は前段で上げたdev.toの記事に紹介されている、リダイレクト先のscopeで有効なsamesite="none"
のcookieを短時間で設定する方法で回避ができました。
ちなみにユーザー情報を連携しない場合はGETでリダイレクトすることが可能な為、上記のような対応で懸念点がある場合にはGETで実装することも可能です。他のサイトも参考に見てみましたが、GETで実装されているサイトが多い印象です。
利用者はメールアドレスの匿名化オプションと、転送停止設定が可能
もう一つ特徴的な機能がメールアドレスの匿名化になります。
エンドユーザーとしては、メールアドレスの流出を防いだり、メールマガジンなどの配信停止を利用するサイトにアクセスする必要無く対応できる点で、とても良い機能に見えました。
以下のような画面で非公開設定が可能で、匿名化されたメールアドレスは以下のような形式になります。
<ランダムな文字列>@privaterelay.appleid.com

運用する側では以下のような対応をする必要があります。
- Appleサイトにて送信元メールアドレスとドメインを登録
- 配信停止から配信再開になった場合を考慮して定期的なbounceリストの削除
2.について少し説明します。
くらしのマーケットではメール送信にSendGridを利用しているのですが、以下の操作をした後にメールを送信し配信に失敗した場合bounceリストに入ってしまいます。
- AppleIDのサイトからメールの転送を無効化
- AppleIDのサイトからアカウント連携を削除

まだ本番ではbounceは発生していないですが、QAテスト時には同じAppleアカウントの連携を削除して、くらしのマーケットのアカウントを削除して、また新しくアカウントを作成してテストなどをしていたので、メールが届かないなどの問題がありました。
こちらはbounceリストから該当のメールアドレスを削除することで対応が可能でした。
最後に
色々とハマりどころがあったのですが、なんとか対応できました。
iOSユーザーにとってはとても良い機能だと思いますので、是非使ってくださいね!