🍎

Sign in with Appleのサーバ通知について

2022/11/24に公開

これはなに

Apple連携(Sign in with Apple)の一環として、サーバ通知(server-to-server notifications)に対応したのでまとめです。

公式ドキュメントにも詳しく書かれているので参考にしてください。
※途中のサンプルコードはRubyです。

サーバ通知とは

サーバ通知とは、「Appleでサインイン」で連携したアカウントの状態が変更された場合に、サーバ側に通知してくれる仕組みです。Apple IDは、スマホやウェブの「Apple IDを使用中のApp」から連携しているアプリを確認できるのですが、ここから連携を解除された場合、アプリ(サービス)側でも連携を解除してあげる必要があります。

通知の種類

現時点で通知の種類(type)は以下の4つです。

type 説明
email-disabled 「メールを非公開」で、メールの転送を無効にした
email-enabled 「メールを非公開」で、メールの転送を有効にした
consent-revoked Apple IDの使用を停止した
account-delete Apple IDのアカウントが削除された
  • consent-revokedaccount-deleteが来た場合、アプリ(サービス)側でも、連携を解除する必要があると思います。
  • AppleIDから取得したメールアドレスに対して、重要な通知などを行なっている場合、email-disabledで転送が無効になったら、ユーザに「転送を有効に戻す」か「メアドを変更する」などの促すことができそうです。

サーバ通知を受けるエンドポイントの設定

エンドポイントの設定はApple DeveloperのApp IDの設定で行います。
Sign in with AppleのEditボタンを押すと

以下のような設定が画面が表示されます。

通知を処理する

次に、Appleからのサーバ通知を処理する流れを説明します。

署名を検証する

サーバ通知のペイロードは、Appleの秘密鍵で署名されたJWS形式です。サーバ側で通知を受信したら、まず署名を検証する必要があります。ヘッダーから署名に使った秘密鍵のキー(kid)を判別して、Appleから公開鍵(jwk)を取得してデコードします。

payload = params[:payload]
headers = JSON.parse(Base64.urlsafe_decode64(payload.split('.')[0]))
jwk = AppleID::JWKS.fetch(headers['kid'])
decoded_payload = JSON::JWS.decode_compact_serialized(payload, jwk)

※公開鍵の取得は、apple_idというgemを利用しています。Sign in with Appleに対応するために必要な処理を提供してくれているとても便利なライブラリです。

ペイロードを検証する

ペイロードがデコードできたら、次は中身をチェックします。
具体的には、以下の2点を検証するといいと思います。

  • aud(送信先)がApp IDと一致しているか decoded_payload[:aud] == 'my_app_id'
  • exp(期限)が切れていないか decoded_payload[:exp] > Time.zone.now

typeに応じて、必要な処理を実装する

ここまでできたら、後は通知の種類(type)によって、必要な処理を実装するだけです。
通知のイベント情報eventsは、JSONになっているので、パースすることでtypeとuidを取得することができます。

events = JSON.parse(decoded_payload[:events])
type = events['type']
uid = events['sub']

余談:ローカルでの開発

ローカルで開発する場合、Appleからのサーバ通知を受けるにはngrokを使うと便利だったので、オススメです。

まとめ

Sign in with Appleのサーバ通知について簡単にまとめてみました。サーバ通知を実装すると、「AppleID側の連携アプリ」とアプリ側の連携状況が正しく同期され、ユーザに正しい情報を提供することができます。

Discussion