Why isn't the user data being returned every time?

I am implementing Sign in with Apple using the JS framework.

When the user (me, right now) signs in for the first time, I get data I need!

The parameters look like this


Parameters:

{"state"=>"[state]", "code"=>"[code]", "id_token"=> "[jws token]", "user"=>"{\"email\":\"[the email I need]\"}"}

My scope is just "email," I don't need (or want) their name.


Next, I try signing in again (same everything)


But, I get this option

When I click "continue" the data looks like this


Parameters:

{"state"=>"[state]", "code"=>"[code]", "id_token"=> "[id token]"}

As you can tell, there is no user object, no email, nothing I can use!



If I do the code response and get an access token, I can't use it. There's no public, known endpoints to just get the email they used. There's no point in storing the email if I can never check for it the next time they sign in.


This is happening on multiple browsers on macOS 10.14.4.



On my iPhone running iOS 13 developer beta 3, every time I click the button, I get the option to "share" or "hide" my email (even though, as shown above, I've sign in before), and sharing the email actually shares it, while hiding it.. well hides it.

However, the user data is always there.



This bug(?) only appears when clicking Continue, which I can assume appears on devices that aren't running iOS 13. It's quite a problem on devices that aren't this small set of devices, so I hope this is either known, easily fixable, or something! Thanks for any help you can provide.

Post not yet marked as solved Up vote post of Chew Down vote post of Chew
26k views

Replies

Hi Chew,


The scopes are only shared once, during the intial authorization. Once the SIWA API returns the information, it is up to the client application to store it within their sytems. For follow up authorizations, the "user" identifier returned as part of SIWA API should be used as a means of fetching the previously shared information from your system.


Once SWIA API returns the information, the application should create an account in its own system, store the information and later use the "user" identifier to retrieve it for follow on authorizations.


Edit:


The data is only returned once for privacy reasons, we do not support an ongoing data sharing.

Thanks Dima, the problem is that if user creation fails for some downstream reason we do not have a way to gracefully recover. The user will be orphaned until they go into iCloud settings and revoke the app permission to force a fresh login.


Conventionally the ID token would contain all in-scope identifying information: name and email in this case. I would also expect to see the real-user confidence value there. Information passed outside the jwt is not signed so cannot be trusted and so not very useful.

@dima_beliy could you share the rational behind the decision to only share the user data once?


This would seem to risk a terrible user experience, should there be any problem the first time a user authorises SIWA.


In my use case (an email address required), any transient problem affecting the user's first attempt to sign in would prevent the user from _ever_ being able to sign up _at all_!


Subsequent SIWA attempts would fail, because Apple has recorded that credential have been sent already, and there is no way for the user to 'reset' this as part of the SIWA flow.


How would the user revoke permisions to allow the credentials to be sent again?

Does Apple offer any guidance on recovering from this error state?


If "ongoing data sharing" is a problem for privacy, surely Apple could snapshot the data the user has already authorised the app to have (at the point of frist login, subsequently possibly stale) and return that in the SIWA REST API response?

You can revoke an authorized client by going to appleid.apple.com. There's a link to unauthorize already authorized apps with SIWA. Then you can try again with the same Apple ID and you'll receive the user JSON payload again. Confirmed it works today.

Thanks kida,


That's helpful to know when developing (also confirmed), but this is not a journey I'm prepared to to send users on.

Absolutely! My answer was only related to how to test this properly during development. In terms of user experience I've done a PoC implementation using SIWA only creating an account once after the initial "user" payload is received and store the user's subject for subsequent logins.


I don't think there is a need to have the "user" returned on every auth.

So basically, in case of any error on our backend while processing the initial authentication the user will be stuck forever. Maybe they'll figure it out and reset trust on Apple ID site and maybe they will contact our support who will help them. Maybe. Most likely they'll just decide that "this app *****". Please fix this, Apple!

Yes, you're absolutely right, this is indeed a problem I already thought of but didn't find a good solution for yet.


One solution would be for Apple to send the "user" payload again in case the server didn't respond with a positive (e.g. <= 399) statuscode. They could also invalidate the issued token then. But then again this could be abused by developers to always request a "user". One way to mitigate this would be to rate-limit failed requests though.


(Also IMO there is heaps of features missing still, e.g. setting an icon if you only want to use SIWA from a Web-App (which I'm currently doing, but an App will follow anyway).

@kida, please could you explain the advantage (as your users will see it) of not sending the user everytime, or allowing apps/sites to request the user in the REST API?


From my perspective:


- It is not privacy, because the user has already chosen to share that data with the app.

- It is not trust (cf. 'abuse', in your message above), because the user has already chosen to trust the app/site the first time round.

- It is not good UX, because it breaks existing patterns from other third party sign-ins that the user may be familiar with, which don't have this limitation (Google, Facebook), and don't require revoke-trust-workarounds on failure.


This just appears to be broken.


Change my view?

I fully agree that revoke-trust-workarounds are a complete UX disaster. Also I'm trying to reason for the current implementation myself and I totally agree that the implementations, currently known through other providers, are more resilient to implement.


Other than the, probably subjective, feeling of only having their e-mail address transmitted once, I can't see any privacy advantages here.

Compared to the chance of a failing webhook, or something on the server going south, the issue produced by this probably outweigh the "benefits".

Same issue as reported by the other developers here. This model of sending the user's data in ID token only once, will not support cases where the client will fail to process the returned token.


Clients can fail for many good reasons and a good Sign In experience cannot involve asking the end user to go to his icloud account and remove the app, and try again.

Could you provide an update on this? As others have stated: by only getting the email the first time it makes the whole system extremely brittle. If anything goes wrong the between the time we receive the response from apple and their account being generated in our system we have effectively lost the user and they will never be able to authenticate (unless they go revoke the app permission with apple and try again which .01% of users will do).


It seems like a straightforward fix. Would you be able to explain:

1. if returning the request scopes with each request is something the team is considering or planning?

2. if no to #1 could you provide the rationale behind this system? Similar oAuth providers (Google, FB, etc) don't have this limitation.

Yes, this is a very bad architecture decision. The internet is not the same thing as the Apple internal netwoek. Sometimes it doesn't work as expected. Regardless of the servers not handling the response or not there's a bunch of other things that can AND DO get in the way. This is going to be very frustrating for the users that get an error and are essentially permanently unable to login to our app. HORRIBLE user experiuence and it does nothing to further privacy.

The email is is being considered to be returned as part of ID token on follow up authorizations. It is currently returned within the ID token on the initial authoriztion only.


Correction: The follow up authorization change is not yet deployed.

This is great but can we also get the name? I see no prvacy implications of providing that as well in a response since this whole process is secure. This falls in line with every other third party login service.