Hey all, I'm encountering persistent issues while attempting to migrate users for an app transfer using Sign In with Apple. I hope to get some insights or solutions from those who might have faced similar challenges.
Context: We're transferring an app from one developer account to another. The app previously only had Sign In with Apple configured for iOS, not for web. We're now trying to set up the user migration process as part of the transfer.
Current Setup:
Old App Bundle ID: old.bundle.id24
Old Team ID: 123456789
New Team ID: 234567890
Issue:
When attempting to generate transfer identifiers for our users, we're encountering an "invalid_client" error. Here's what we've observed:
-
Using old_client_id = 'old.bundle.id24': Successfully generates an access token but fails at the user migration info step with an "invalid_client" error.
-
Using old_client_id = 'old.bundle.id' (without '24'): Fails to generate an access token with an "invalid_client" error.
Simplified script I am using
old_client_id = 'old.bundle.id24'
old_team_id = '123456789'
new_team_id = '234567890'
# JWT Payload for client secret
jwt_payload = {
'iss': old_team_id,
'iat': int(time.time()),
'exp': int(time.time()) + 15552000, # 180 days
'aud': 'https://appleid.apple.com',
'sub': f'{old_team_id}.{old_client_id}'
}
# Generate client secret
client_secret = jwt.encode(jwt_payload, private_key, algorithm='ES256', headers={'kid': key_id, 'alg': 'ES256'})
# Request access token
token_response = requests.post('https://appleid.apple.com/auth/token',
data={
'grant_type': 'client_credentials',
'scope': 'user.migration',
'client_id': old_client_id,
'client_secret': client_secret
},
headers={'Content-Type': 'application/x-www-form-urlencoded'}
)
# If successful, proceed to user migration info request
if token_response.status_code == 200:
access_token = token_response.json()['access_token']
migration_response = requests.post('https://appleid.apple.com/auth/usermigrationinfo',
data={
'sub': user_sub,
'target': new_team_id,
'client_id': old_client_id,
'client_secret': client_secret
},
headers={
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/x-www-form-urlencoded'
}
)
# This is where we get the "invalid_client" error
print(migration_response.status_code, migration_response.text)
What we've tried:
-
Verified all IDs (client ID, team ID, key ID) match between our code and the Apple Developer portal.
-
Ensured the JWT is correctly signed with the ES256 algorithm.
-
Checked that the client secret hasn't expired.
-
Verified the content type is set correctly for all requests.
-
Waited 72h+ since the key was first generated.
Questions:
-
Could the lack of web configuration in the original app be causing this issue? If so, how can we rectify this post-transfer?
-
Is there a specific way to handle migrations for apps that were only configured for iOS Sign In with Apple?
-
Are there any known issues or additional steps required when the old and new bundle IDs differ slightly (e.g., with/without '24' at the end)?
-
How can we further diagnose the root cause of this "invalid_client" error, given that it occurs at different stages depending on the client ID used?
Any insights, suggestions, or solutions would be greatly appreciated - I really don't know what to try at this point... Thank you in advance for your help!
First, I'd recommend reading the following post about troubleshooting Sign in with Apple user migrations:
Gathering required information for troubleshooting Sign in with Apple user migration https://developer.apple.com/forums/thread/762829
I also noticed the following line in your request:
'sub': f'{old_team_id}.{old_client_id}'
I just want to confirm that this would output only the bundle ID of the app, correct? We do not expect the Team ID prefix and including it will always fail validation.
Now, to your questions:
- Could the lack of web configuration in the original app be causing this issue? If so, how can we rectify this post-transfer?
No. The user migration process would work for any client ID, as long as the associated client secret is valid for each team included in the app transfer. Having an associated web configuration, or a lack thereof, would have no effect either way..
- Is there a specific way to handle migrations for apps that were only configured for iOS Sign In with Apple?
No, the process you are following is the only way to migrate users after the transfer of a Sign in with Apple enabled app.
- Are there any known issues or additional steps required when the old and new bundle IDs differ slightly (e.g., with/without '24' at the end)?
The app's bundle ID isn't expected to change during an app transfer. Could you please explain a bit about why and how this happened?
- How can we further diagnose the root cause of this "invalid_client" error, given that it occurs at different stages depending on the client ID used?
The invalid client error means that the client could not be validated—looking at the implementation, this could be due to the invalid sub
claim in the client_secret
, or the unexpected change of the client_id
for the recipient (new) team's requests.
To learn more about the response errors, please see the following technote:
Resolving Sign in with Apple response errors https://developer.apple.com/documentation/technotes/tn3107-resolving-sign-in-with-apple-response-errors
Cheers,
Paris X Pinkney | WWDR | DTS Engineer