2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CYBIRD Advent Calendar 2024Advent Calendar 2024

Day 22

Sign in with Apple のユーザーを別のチームに移行してみる

Last updated at Posted at 2024-12-21

CYBIRD Advent Calendar 2024 22日目担当の@cy-tsuzawaです。
21日目は@R_araiさんの「AGPの更新でBuildConfig.VERSION_CODEが参照出来なくなったお話」でした。

はじめに

普段はサーバーサイドエンジニアをしています。
今回、Sign in with Apple を使用しているアプリを別の開発者チームに移行する機会があり、その時に直面した課題やおこなった作業について書いていきたいと思います。

概要

Sign in with Apple を使用しているサービスを別の開発者チームに移行する場合、移行後に既存のアカウントにログインできない状況が発生することがあります。
原因として、Sign in with Apple を使用してユーザーが認証をおこなう際に、「メールを非公開」を選択するとprivaterelay.appleid.comのようなメールアドレスが自動生成されるのですが、生成にチームIDやキーID等のチーム固有の情報が使用されるためとなります。

ちなみに自動生成されたメールアドレスは以下で確認できます。

iPhoneの設定 > Apple ID > サインインとセキュリティ > Apple でサインイン > 対象のアプリ

Appleにて移行手順について詳細な記事が公開されていますが、結構手順が多く準備に時間がかかるので注意が必要です。

準備

記事を確認すると、以下の手順が記載されています。

  • ユーザーアクセストークンを取得する
    • client_secret (JWT) の生成
  • 転送識別子を生成する
  • 移行先のチームに転送識別子を共有

それぞれ1つずつ実行していきます。

ユーザーアクセストークンを取得する

ユーザーアクセストークンを取得するには、移行元の client_idclient_secret を取得する必要があります。

client_idは、App ID または Services IDを指定します。Sign in with Apple を使用しているのがアプリなのかWebなのかで指定するIDが変わります。

client_secretの取得には、JWTの生成が必要なため次の項目で説明します。

client_secretを取得する

client_secretこちらに生成手順が記載されています。
生成には、以下の情報が必要です。Apple Developer サイトで確認できます。

情報が揃ったら、kidの秘密キーで署名されたJWTを作成します。
Pythonで作成してみました。

import pathlib
from datetime import datetime, timezone, timedelta
import jwt
    
header = {
    "alg": "ES256",
    "kid": kid
}
payload = {
    "iss": iss,
    "iat": datetime.now(timezone.utc).timestamp(),
    "exp": (
        datetime.now(timezone.utc) + timedelta(days=1)
    ).timestamp(),
    "aud": "https://appleid.apple.com",
    "sub": sub
}
client_secret = jwt.encode(
    payload,
    (pathlib.Path('secrets/AuthKey_XX.p8')).read_text(),
    algorithm="ES256", 
    headers=header
)

これでclient_secretの準備ができました。

ユーザーアクセストークンをPOSTメソッドで取得する

client_idclient_secret が取得できたので、ユーザーアクセストークンを取得します。

import requests

access_token_response = requests.post( 
    "https://appleid.apple.com/auth/token", 
    data=dict( 
        grant_type="client_credentials", 
        scope="user.migration", 
        client_id=client_id, 
        client_secret=client_secret 
    ),
    headers={"Content-Type": "application/x-www-form-urlencoded"}
) 
access_token = access_token_response.json()

以下のようなレスポンスが返ってくれば成功です。

{
  "access_token":"XXXXXXXXXXXXX",
  "token_type":"Bearer",
  "expires_in":3600
}

転送識別子を生成する

ユーザーアクセストークンの取得ができたら、やっと転送識別子の生成です。
今まで使用した情報の他に、以下の情報が必要になります。

  • sub:Apple が提供するチームスコープのユーザー識別子。000000.00000000000000000000000000000000.0000のような構成
  • target:移行先のチームID
transfer_sub_response = requests.post( 
    "https://appleid.apple.com/auth/usermigrationinfo", 
    headers={"Authorization": "Bearer " + access_token['access_token']}, 
    data=dict( 
        sub=sub, 
        target=target,
        client_id=client_id,
        client_secret=client_secret
    ) 
)
transfer_sub = transfer_sub_response.json()

以下のようなレスポンスが返ってくれば成功です。

{
  "transfer_sub":"XXXXXXXXXXXXX"
}

移行先のチームに転送識別子を共有

ユーザー分の転送識別子の生成が終わったら、転送識別子を移行先に共有します。
移行先は転送識別子を使用して、ユーザーの移行先でのメールアドレスを取得することができます。

最後に

Sign in with Apple を使用したサービスを開発する機会は多いと思うのですが、ユーザーの移行の機会はほとんどないので、貴重な経験となりました。
移行後の猶予が60日間となっているので、計画的な準備・移行作業をおすすめします。
ここまで読んでいただきありがとうございました!

明日のCYBIRD Advent Calendar 2024 23日目は@cy-yamakenさんの記事です。お楽しみに!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?