Was just implementing AppleAuthentication and have the entire flow working well. However I can’t test the validation of the JWT token because that would require the public key of the Apple ID Key.
Would it be possible for you to provide that for users testing using the Expo app? Basically you take the private p8 file that you would have downloaded when setting up your key in the apple console and you would run this:
Hi - We’ll take a look at this. It should be secure to share the public key (after all, it’s public) but we may rotate the p8 key over time and without any warning since we might not be able to anticipate needing to rotate it, so it’s not something you should rely on in production services. Of course, you can rely on your own p8 key for your own standalone apps.
In short, use Apple’s own public key to verify “Sign In with Apple” JWTs. The public key is here: https://appleid.apple.com/auth/keys. There is a JWT debugger on the front page of https://jwt.io/ that lets you paste in a JWT and a key – copy & paste your JWT and just one of the keys (not the whole response) from Apple into that form. I tested it and verified the signature correctly. This has nothing specific to do with Expo so you can use whatever approach and tools you’d use otherwise.
I’m so sorry. I had written this reply to myself but I somehow didn’t post it. Again, so sorry, but you are totally correct. I was able to validate with the Apple JWK.
Follow up to myself.
You don’t need the public key specifically from your Apple Key, you need Apple’s public key. They provide a JWK set (JSON Web Key Set) here: https://appleid.apple.com/auth/keys
Hi, @theorytank. Sorry to hijack your thread but I’m completely blocked with Sign in with Apple at the moment and I’m really struggling to find some help.
Right now, I followed the Expo docs and set up what was needed in my Apple Developer account and when I try to sign in (with Apple), I get the expected credential (authorizationCode, name, email, identityToken, etc.). I sent this to my server and from there I want to validate the authorizationCode with Apple before signing up the user or signing them in.
In Apple’s docs, they mention using their auth endpoint but despite apparently creating the secret correctly, I still get a 400 Bad Request (“invalid_grant”) back from Apple. Is this how you’re validating the code? If not, could you please help me out as I’ve been stuck on this for a few days now. I know that Apple expect a redirect_uri when validating on that endpoint and I’ve seen some people using this when setting up Apple auth on a website but I haven’t seen it with an Expo app. Any advice would be welcome. Thanks.
Apples docs aren’t very clear but you’re looking at “AppleID using OAuth” documentation which is only relevant when you use “Sign In With Apple” from a browser, not from a native app.
You’re doing everything right so far. Send the payload to your server as you’re doing. Then get the JWK (JSON Web Key) from this endpoint https://appleid.apple.com/auth/keys (probably best to cache the result for a while if you have high traffic, it really should never change, but it might).
Now you have everything you need to validate the original payload. No more REST calls required. Everything can be done locally from your server.
So, TL;DR; Use Apple’s JWK to validate your JWT payload on the server side using just those two piece of info. Useful google would be using a jwk to validate a jwt and include your language of choice.
What I found when trying it the other way – hitting Apple’s auth endpoint – is that the invalid_grant was very likely related to me testing in Expo as opposed to in a standalone build. That is, the app id was being sent as host.exp.Exponent as opposed to that of my app. I read somewhere that this is the case with Expo and to test properly you should push a build to TestFlight but I’m not ready to do that.
If you look in this article about Sign in with Apple on an Expo app (and you check the comments between myself and the author as we go back and forth about it a bit), he seems to have it working via the endpoint and he doesn’t do any of the manual checking using Apple’s Public Key. He mentions having to use TestFlight and that it definitely doesn’t work in the Expo app.
Regardless, I’ve also actually tried a way similar to the one you suggested (checking the token using Apple’s JWK) and when comparing the aud, it’s not matching my id (let’s call it .com.myApp.app); it’s actually getting host.exp.Exponent (which doesn’t match my id) so just like the first approach, it seems like this is related to running the app in Expo, right? I guess, for now, like you, I’ll also allow it to match host.exp.Exponent.
Thanks again for your comprehensive reply, by the way, and apologies for the delayed response. Have a nice day and week ahead.
I’ve used Josh’s implementation above - and Im able to get an email from the JWT which I then use to validate against the DB, I wanted to ask about caching the $keys response from apple.
At the moment I get something similar to this AIDOPK1 => resource id='17' type='OpenSSL key' is that expected?
Second if I saved that data to a database and used the database data instead of fetching from apple, I might run into a situation where users were using updated apple keys and the decoding would fail right - what would that look like what kind of error would I get and how could I simulate that?
further to the above, say the decoding failed, would I then use another tryCatch statement with the new details fetched from apple and persist those alongside my existing data?