Sign in with Apple

Are we sure that it will return a name? From a privacy perspective it’s almost better if the user picks a name than have any public PII disclosed in the process.

It should do technically? But agree with your point, though you can choose not to expose it at the Apple page. Moot, as it turns out so far!

Yes, someone had raised an issue about this, but it was then closed.

I’ve commented on it

I’m guessing this is the area of code we’re concerned about?:

      info do
        { sub: id_token['sub'] }
      end

whereas in the discord auth gem, for example, we get this:

      info do
        {
          name: raw_info['username'],
          email: raw_info['verified'] ? raw_info['email'] : nil,
          image: "https://cdn.discordapp.com/avatars/#{raw_info['id']}/#{raw_info['avatar']}"
        }
      end

FYI No mention of those fields in Apple’s API documentation …

https://developer.apple.com/documentation/signinwithapplerestapi/tokenresponse

It looks like this PR adds the useful user information: https://github.com/nhosoya/omniauth-apple/pull/7. Hopefully it will be merged soon, or if not we could look at using a fork

5 Likes

Yes, you are right, I’d seen that PR but not dug into the code and thought it was simply switching to a different dependency. People should consider not PR-ing with such huge scope as details like that can be lost.

As you said:

        {
          sub: id_info['sub'],
          email: user_info.dig('email'),
          first_name: user_info.dig('name', 'firstName'),
          last_name: user_info.dig('name', 'lastName'),
          extra: {
            raw_info: id_info.merge(user_info)
          }
        } 

I’ve added a comment to support the PR.

4 Likes

@David, the author of the PR has responded to my comment, what’s your opinion on this?:

Me:

This PR appears to solve the issue with the lack of name and email?

PR Author:

No, unfortunately not. Apple needs to provide a REST API endpoint to retrieve name/email as they currently only pass this information upon successful authentication once and not on subsequent authentications.

Isn’t one-time at initial Authorisation good enough for us?

It’s better than nothing, but it’s still not good. For example, if you “sign in with apple”, but then click cancel on the “create account” screen. Or if you connect an existing account with apple, then decide to create a new account instead. Hopefully Apple will resolve that before the end of the beta :crossed_fingers:

5 Likes

Is there a working implementation of the Sign in with Apple feature at this stage? A site I’m doing marketplace work for plans to have an iOS app however without this option, we can’t enable other auth options unless we want our app to be rejected for violations of app guidelines.

No that I’m aware of. We’re waiting for this issue to be resolved https://github.com/nhosoya/omniauth-apple/issues/8, though the repo owner has unhelpfully closed it.

I’m not too sure but don’t commits like this one and the other commits from August resolve the issue?

Feel free to install the plugin to test but I’m not aware that’s yet resolved. I would not recommend using it in Production though until it’s finished or at least signed off by a developer with some time to confirm things.

I’m a huge advocate for this feature. I’d love to see it be built into vanilla Discourse like the other sign-in options.

I think you cannot retrieve that kind of information on purpose.

Displaying a Sign in with Apple button in your app or website means that people can sign in or sign up with just a tap using the Apple ID they already have, and skip filling out forms, verifying email addresses, and choosing passwords. Sign in with Apple provides a new, more private way to simply and quickly sign into apps and websites while giving people a consistent sign-in experience they can trust and the convenience of not having to remember multiple accounts and passwords. In cases where you choose to ask for a name and email address, people have the option to keep their email address private and share a unique, random email address instead.

See the full developer article by Apple

You’re right, privacy is one of the key parts of Sign In with Apple, but the key part of your quote is:

Assuming people choose to give us name/email, then we would expect to receive it from the provider every time the user logs in. In the current implementation, this doesn’t happen. After the first authentication, we get no user information.

I don’t think this is something the gem author can fix - it’s something Apple would need to change. I can’t see that happening any time soon, so maybe we just need to ask users to enter their name/email in Discourse manually :cry:

4 Likes

Yes, but what about the people who end up choosing not to give their information?

Oh, and here’s a crude concept. :sweat_smile:

Good news:

I partially got a fork of Robert/merefield’s plugin working (the fork only involves switching to a copy of the omniauth gem that I built from the latest source on GitHub). However, on my test Discourse (which has HTTPS end-to-end via ngrok), I had to set the same site cookies Site Setting to (none) in order for auth to work. With the setting disabled, I can create an account (even if I closed the signup form) and can log back in however I’m unable to do so if the setting is enabled.

Backtrace from a failed login attempt is below:

Failed login backtrace
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/logger.rb:112:in `report_to_store'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/logger.rb:103:in `add_with_opts'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/logger.rb:54:in `add'
/usr/local/lib/ruby/2.6.0/logger.rb:543:in `error'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:163:in `log'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:486:in `fail!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-oauth2-1.6.0/lib/omniauth/strategies/oauth2.rb:71:in `callback_phase'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:238:in `callback_call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:189:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/builder.rb:64:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:47:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/tempfile_reaper.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/conditional_get.rb:38:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/head.rb:12:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:318:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/session/abstract/id.rb:259:in `context'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/session/abstract/id.rb:253:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/cookies.rb:648:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:101:in `run_callbacks'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.5.1/lib/logster/middleware/reporter.rb:43:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/rack/logger.rb:38:in `call_app'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:18:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/method_override.rb:22:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/executor.rb:14:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/sendfile.rb:111:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-6.0.1/lib/action_dispatch/middleware/host_authorization.rb:77:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.1.4/lib/mini_profiler/profiler.rb:184:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/message_bus-2.2.3/lib/message_bus/rack/middleware.rb:57:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:181:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/engine.rb:526:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/railtie.rb:190:in `public_send'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-6.0.1/lib/rails/railtie.rb:190:in `method_missing'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/urlmap.rb:68:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/urlmap.rb:53:in `each'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.8/lib/rack/urlmap.rb:53:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:605:in `process_client'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:700:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:548:in `spawn_missing_workers'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/lib/unicorn/http_server.rb:144:in `start'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.2/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `load'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `<main>'

Does anyone here have any suggestions on if/how I can re-write the plugin to no longer require disabling this site setting for its core functions to work? My plugin code lives at https://github.com/sau226dev/discourse-sign-in-with-apple and the latest code I used for rebuilding the omniauth gem should be in the same GitHub organization.

Thanks for any help you can provide in advance,

sau226

4 Likes

The plugin originally worked to an extent but has not received attention recently because of the issue described by David above.

Until we receive positive news that Apple has resolved that fundamental blocker (sending name and email on every login attempt) it’s not worth maintaining this code imho. I don’t believe there is anything you can do to get around it? That is why I haven’t even attempted to update the dependencies. The plugin would fail testing in any case.

So this not a ‘released’ plugin (otherwise this or a similar topic would live in #plugin) and it’s not likely to receive any support until that happens. I would be delighted to ‘polish it off’ if that issue was resolved and Apple were to provide that info.

There is also another significant issue btw: in order to use it for ones own site you need to pay up for the Apple Developer Programme to get access to the setup on Apple’s systems. This is going to put a lot of low budget sites off I suspect as that is not a free/low price sign up.

6 Likes

I believe @sau226 would seem to suggest the lack of returned email/name is not, in fact, a blocker?

@orenwolf It (the lack of returned email/name on subsequent log ins) did not appear to be an issue. I believe that I was able to close the sign up window and resume sign up with correct details passed in. As I stated before, I was able to log in with Apple afterwards straight away with no issue.

The only issue I faced was the CSRF error unless the site setting I mentioned above was disabled. One potential issue is the lack of a name on the sign in form and that the username is whatever is before the @ sign in the email (however if you ask me, these potential issues are either a non issue or can be easily fixed by the user).

4 Likes

In addition to David’s comments above I found a related topic on Apple’s developer support site which attracted an official response that confirms the issue:

https://forums.developer.apple.com/thread/121496

Official Response:

Hi aslkdjalksdjasdasd,
This behaves correctly, user info is only sent in the ASAuthorizationAppleIDCredential upon initial user sign up. Subsequent logins to your app using Sign In with Apple with the same account do not share any user info and will only return a user identifier in the ASAuthorizationAppleIDCredential. It is recommened that you securely cache the initial ASAuthorizationAppleIDCredential containing the user info until you can validate that an account has succesfully been created on your server.
Patrick

As one developer comments:

So wait… If for some reason the first redirect from Apple gets lost for one of many VERY common reasons then we’ve permanently lost that user since there’s no other way to get their information. There is NO other way to get this info?

and another:

Or if something goes wrong downstream, we would have the customers complaining and support will tell them to go into AppleId website to revoke the permission, so they can properly register again. I believe this will be a poor experience and will make people not using this login mechanism if they start having this sort of problems.

So I don’t think you can safely use this in Production, sadly. This would be a support nightmare.

I suggest we put this to sleep until Apple wakes up to the problem they’ve created: in their attempt to improve security it seems they’ve over-compromised robustness.

11 Likes

That’s a bummer. :cry:

1 Like