Search code examples
iosoauthopenid-connectapple-id

Obtaining user's email using Apple's IdentityToken


On my mobile app I use apple-id authorization. My implementation uses ASAuthorizationAppleIdProvider class and does not require additional proxy web-application, that sends request to Apple. All interaction is done on the mobile client.

All things work ok, and I get authorized and I get IdentityToken from Apple.

Now, I want to send this IdentityToken (looks like "AjzN91mNajN3401jazOs001m3ks") to the server. And on the server side I want to extract user's email from this token.

For Google to solve the same task I have to send GET request with token, like that

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=google_token

and if token is valid in response I get JSON with user's email inside.

How can I do the same for the Apple using Apple's identity key?


Update #1:

My project has 2 parts, client part (frontend) and server part (backend).

The functionality to obtain IdentityToken looks like that (AuthManager is just a delegate):

var provider = new ASAuthorizationAppleIdProvider();
var req = provider.CreateRequest();

authManager = new AuthManager(UIApplication.SharedApplication.KeyWindow);

req.RequestedScopes = new[] {
  ASAuthorizationScope.FullName,
  ASAuthorizationScope.Email
};
var controller = new ASAuthorizationController(new[] {
  req
}) {
  Delegate = authManager,
  PresentationContextProvider = authManager
};

controller.PerformRequests();

ASAuthorizationAppleIdCredential credentials = await authManager.Credentials;

When I get credentials, there is credentials.IdentityToken property available.

Now, I want to send this identity token to the server, to let the server check this token and obtain user's email using this token from the Apple server, like I do for Google (described above).

And I do not understand, how can I do that.

What Apple endpoint and what HTTP request (GET, POST) should be used to achieve this task?


Solution

  • In OpenID Connect, the Identity Token is never sent to the Provider. I think this is just a typo/naming issue and you mean the Access Token.

    The end result of the user authenticating is two tokens:

    1. the Access Token, an opaque token which is not meant to be introspected by the Client. It may or may not be a JWT.
    2. an ID Token, a JWT which contains the user claims.

    To obtain the user's email address, decode the ID/Identity Token's JWT payload. To do this in Swift, see these SO answers. The JWT should contain an email value. It looks like the email address may also be an instance property of ASAuthorizationAppleIdProvider, so you should be able to get them from credentials.email.

    There does not appear to be a way to directly validate the Access Token. Most OpenID Connect Providers offer a Userinfo Endpoint, or a Token Instrospection Endpoint (I think this is the Google endpoint that was linked in question), but Apple does not. A number of steps were already performed to obtain the Access Token, however, which should make it impossible to forge. If you really only want the email address, though, JWTs are cryptographically signed, so verifying the JWT should guarantee it was issued by Apple. You can also verify the Refresh Token as shown in Apple Developer docs. In your code above, I don't see a way to access Refresh Token, but if you followed an alternative flow as shown in one of the tutorials here or here, you would be able to.