简体   繁体   中英

Sign In with Apple, decoded Apple response

I've implemented 'Sign In with Apple' from this source ( https://gist.github.com/aamishbaloch/2f0e5d94055e1c29c0585d2f79a8634e?permalink_comment_id=3328115 ) taking into account the comments of NipunShaji and aj3sh. But it doesn't works because Apple sends incomplete data: I recieve

decoded = {'iss': 'https://appleid.apple.com', 'aud': '...', 'exp': 1664463442, 'iat': 1664377042, 'sub': '.....', 'at_hash': '....', 'auth_time': 1664377030, 'nonce_supported': True}

without email data).

According to the Apple's documentation typical response contains email: https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple .

What I've missed?

Additional code:

view.py file :

class AppleSocialAuthView(GenericAPIView):
serializer_class = AppleSocialAuthSerializer
permission_classes = [AllowAny]

def post(self, request):
    """
    POST with "auth_token"
    Send an access token as from facebook to get user information
    """

    serializer = self.serializer_class(data=request.data)
    serializer.is_valid(raise_exception=True)
    data = (serializer.validated_data['auth_token'])
    return Response(data, status=status.HTTP_200_OK)

serializer.py file :

class Apple(BaseOAuth2):
"""apple authentication backend"""

name = 'apple'
ACCESS_TOKEN_URL = 'https://appleid.apple.com/auth/token'
SCOPE_SEPARATOR = ','
ID_KEY = 'uid'

@handle_http_errors
def do_auth(self, access_token, *args, **kwargs):
    """
    Finish the auth process once the access_token was retrieved
    Get the email from ID token received from apple
    """
    response_data = {}
    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': settings.SOCIAL_AUTH_APPLE_REDIRECT_URL
    }

    res = requests.post(Apple.ACCESS_TOKEN_URL, data=data, headers=headers)
    response_dict = res.json()
    id_token = response_dict.get('id_token', None)

    if id_token:
        decoded = jwt.decode(id_token, '', options={"verify_signature": False}, verify=False)
        print(decoded)
        response_data.update({'email': decoded['email']}) if 'email' in decoded else None
        response_data.update({'uid': decoded['sub']}) if 'sub' in decoded else None

    response = kwargs.get('response') or {}
    response.update(response_data)
    response.update({'access_token': access_token}) if 'access_token' not in response else None

    kwargs.update({'response': response, 'backend': self})
    return self.strategy.authenticate(*args, **kwargs)

def get_user_details(self, response):
    email = response.get('email', None)
    details = {
        'email': email,
    }
    return details

def get_key_and_secret(self):
    headers = {
        'kid': settings.SOCIAL_AUTH_APPLE_KEY_ID,
        'alg': 'ES256',
    }

    payload = {
        'iss': settings.SOCIAL_AUTH_APPLE_TEAM_ID,
        'iat': int(time.time()),
        'exp': int(time.time()) + 15552000,
        'aud': 'https://appleid.apple.com',
        'sub': settings.SOCIAL_AUTH_APPLE_CLIENT_ID,
    }

    client_secret = jwt.encode(
        payload,
        settings.SOCIAL_AUTH_APPLE_CLIENT_SECRET,
        # algorithm='ES256',
        headers=headers
    )

    return settings.SOCIAL_AUTH_APPLE_CLIENT_ID, client_secret

class AppleSocialAuthSerializer(serializers.Serializer):
auth_token = serializers.CharField()

def validate_auth_token(self, auth_token):
    user_data = Apple()
    user_data = user_data.do_auth(auth_token)
    try:
        email = user_data['email']
        name = user_data['name']
        provider = 'apple'

        return register_social_user(
            provider=provider, email=email, name=name)
    except Exception as identifier:

        raise serializers.ValidationError(
            'The token  is invalid or expired. Please login again.'
        )

When I test this proces on my Mac (logging into web app), the end result is that I can see on my Mac, preferences -> Apple ID, that I'm using SSO for this application.

So it looks like Apple validated this Web App.

If they do send email, only first time the user is logging in to Web App, how Web App should know next time what user to log in?

There is no single parameter that would identify the user in decoded response (like some ID, which would also appear in their first response?

Best Regards, Marek

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM