Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apple Signin through Python

Tags:

python

ios

jwt

I do have a problem with apple signin in python but it's mostly not python, just mysterious stuff.... So, I read this article https://medium.com/@aamishbaloch/sign-in-with-apple-in-your-django-python-backend-b501daa835a9 It should be quite easy to implement it but my implementation doesn't work, so what I did is: I've added appleapiprovider class which being used in rest framework, this AppleProvider being called this way:

provider = AppleApiProvider()
provider.verify_token(token_sent_from_ios_device) # NOT JWT TOKEN, just code.

and here is what happening in the method verify_token

def verify_token(self, token):
    client_id, client_secret = self.get_key_and_secret()
    headers = {'content-type': "application/x-www-form-urlencoded"}
    data = {
        'client_id': client_id,
        'client_secret': client_secret,
        'code': access_token,
        'grant_type': 'authorization_code',
        'redirect_uri': 'https://example-app.com/redirect'
    }
    res = requests.post('https://appleid.apple.com/auth/token', data=data, headers=headers)

    def get_key_and_secret(self):
        headers = {
            'kid': KID
        }

        payload = {
            'iss': ISS,
            'iat': timezone.now(),
            'exp': timezone.now() + timedelta(days=180),
            'aud': 'https://appleid.apple.com',
            'sub': 'com.APP.staging.signin',
        }

        client_secret = jwt.encode(
            payload,
            open('/etc/apple.pem', 'rb').read(),
            algorithm='ES256',
            headers=headers
        ).decode("utf-8")

        return 'com.APP.staging.signin', client_secret

And in result I get

{error: 'invalid_grant'}

Any idea ? It's not a problem with client_id and client_secret, I tried to use there just absolutely random strings and it says, invalid_client Possible duplicate is: New Apple Sign in keeps throwing Error HTTP 400 Invalid_grant but there's no exact solution to my problem, it should be quite small and I don't know how to debug it.

like image 626
Sergey Glazyrin Avatar asked Mar 31 '26 20:03

Sergey Glazyrin


1 Answers

My error was using the JWT token as the 'code' parameter instead of the authorization_code.

I am using the '@invertase/react-native-apple-authentication' React Native package to handle Apple Sign in on client side. I think the data transmitted there may be similar across Native and other packages.

What this package returns on apple sign-in is the following object:

{
  authorizationCode: string <- this should be sent as "code"
  authorizedScopes: [],
  email: string <- will be null, except for first request. To reset for testing, disconnect the app from apple signin
  fullName: {...} <- will contain null values only, except for first request. see above
  identityToken: string
  nonce: string
  realUserStatus: 1
  state: ?
  user: string  <- should be used to identify users
}

The identityToken is a JWT token that when decoded contains the following data:

header:
{
  "kid": string, <- can be used to identify the apple public key one can use to verify the signature (fetched from here https://appleid.apple.com/auth/keys)
  "alg": "RS256"
}

payload:
{
  "iss": "https://appleid.apple.com",
  "aud": <your package ID>,
  "exp": number,
  "iat": number,
  "sub": string, <- same as "user" in above datastructure
  "nonce": string,
  "c_hash": string,
  "email": "[email protected]", <- contains the email, even if the above structure does not contain it
  "email_verified": "true",
  "is_private_email": "true",
  "auth_time": number,
  "nonce_supported": true
}

One confusing aspect is, that the email can be null in the first obj, but still be contained in the JWT. It is a bit unclear whether we need the JWT token in all cases. It seems like for a simple authentication service the authorizationCode and user parameters suffices.

like image 93
David Schumann Avatar answered Apr 03 '26 11:04

David Schumann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!