Disgusting things during the integration of Apple account login

该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/en/post/2025/01/04/connect-to-apple-account/

A few days ago, I finished the integration of Microsoft account and Apple account login functions for our system. The Microsoft’s system meets the standard OAuth2.0 + OpenID Connect protocol, so it can be simply integrated with a general module for OAuth2.0 and OpenID Connect.

However, Apple is always the one who makes things disgusting.

1. Generating the OAuth2.0 client secret

For Google, Microsoft, and Facebook, the Client ID and Client Secret are simply provided as plain strings, which can be used directly.

When you meet Apple, things are completely different. After registering an OAuth2.0 application, you will get a Client ID, and an ECDSA private key, no pre-generated Client Secret.

To get a Client Secret, you need to sign a JWT Token with the ECDSA private key, and then use it as the Client Secret.

Well, this means that you have to develop a set of logic specifically for integrating Apple accounts, and the existing OAuth2.0 integration module cannot be used without modification.

Sure, here is always some tricks: you can sign a long-term JWT Token, and use it as the Client Secret. In this way, you don’t need to generate a new Token every time, at least you can update it by intervals. Just like what Microsoft does, its Client Secret is also time-limited.

2. Receiving the authorization code

In most cases, for the authorization code mode of OAuth2.0, after the user agrees to authorize, the browser will be redirected to the redirect_uri you specified, and the authorization code will be passed as a parameter in the query string of the redirect_uri. And the request is made by the HTTP GET method by default.

Microsoft provides an option to specify the response_mode as form_post in authorization starting link. In this way, the authorization code will be sent by the HTTP POST method in the HTTP entity instead of query-string, but the default method is still GET.

As you can see, Apple is always different. It says in the document: When any non-empty scope is specified, it will always send the authorization code by the HTTP POST method, not by the GET method.

You need to add a POST request processing logic to the existing OAuth2.0 integration module for Apple account login.

3. Retrieving the real email address of Apple accounts

Because of some requirements in our team, when creating a new account with a third-party account, a verified email address is required (read from the third-party account). If it’s binding a third-party account to an existing account, the email address is not required.

Apple makes another mess here. It says:

  • If the user chooses Hide My Email when authorizing, you cannot get the real email address, but only a proxy email address provided by Apple.

    You could still receive emails sent to the proxy email address, because they will be forwarded to your real email address.

  • If the user has authorized our application before, the real email address will not be passed again when the user login again by Apple account.

What’s matter?

The first rule doesn’t matter at all, you could check the is_private_email field in the id_token to determine if it’s a proxy email address, and then refuse it.

Just look at the second rule. It’s a little disgusting.

When you receive the id_token, the binding of users’ Apple account and your App is already completed, in Apple side. If your system fails after this point, and the authorization information is not saved successfully into your system, the user will never be able to log in with Apple account again, unless they manually revoke the authorization in their Apple account, which creates terrible user experience.

To be honest, I don’t blame Apple for this:

  • It’s the user’s privacy information, and it’s okay to pass as little as possible;

  • If the authorization process fails, the system should remove the incomplete authorization records from both its system and the third-party system.

    Not always work. The Microsoft account system does not provide an API to revoke the authorization from the application side, only the user can revoke it. Fortunately, Microsoft always passes the email address every time, so this problem will not occur.

Anyway, the second rule is not an easy problem to solve, and many OAuth2.0/OIDC integration modules may not handle this situation.

The developers need a highly effective solution for this problem.

comments powered by Disqus

Translations: