Skip to content

Instantly share code, notes, and snippets.

@davidhariri
Created October 12, 2019 18:14
Show Gist options
  • Save davidhariri/b053787aabc9a8a9cc0893244e1549fe to your computer and use it in GitHub Desktop.
Save davidhariri/b053787aabc9a8a9cc0893244e1549fe to your computer and use it in GitHub Desktop.
Code required to verify Sign in with app-made Apple JWT tokens server-side in Python
import jwt
from jwt.algorithms import RSAAlgorithm
import requests
from time import time
import json
import os
APPLE_PUBLIC_KEY_URL = "https://appleid.apple.com/auth/keys"
APPLE_PUBLIC_KEY = None
APPLE_KEY_CACHE_EXP = 60 * 60 * 24
APPLE_LAST_KEY_FETCH = 0
class AppleUser(object):
def __init__(self, apple_id, email=None):
self.id = apple_id
self.email = email
self.full_user = False
if email is not None:
self.full_user = True
def __repr__(self):
return "<AppleUser {}>".format(self.id)
def _fetch_apple_public_key():
# Check to see if the public key is unset or is stale before returning
global APPLE_LAST_KEY_FETCH
global APPLE_PUBLIC_KEY
if (APPLE_LAST_KEY_FETCH + APPLE_KEY_CACHE_EXP) < int(time()) or APPLE_PUBLIC_KEY is None:
key_payload = requests.get(APPLE_PUBLIC_KEY_URL).json()
APPLE_PUBLIC_KEY = RSAAlgorithm.from_jwk(json.dumps(key_payload["keys"][0]))
APPLE_LAST_KEY_FETCH = int(time())
return APPLE_PUBLIC_KEY
def _decode_apple_user_token(apple_user_token):
public_key = _fetch_apple_public_key()
try:
token = jwt.decode(apple_user_token, public_key, audience=os.getenv("APPLE_APP_ID"), algorithm="RS256")
except jwt.exceptions.ExpiredSignatureError as e:
raise Exception("That token has expired")
except jwt.exceptions.InvalidAudienceError as e:
raise Exception("That token's audience did not match")
except Exception as e:
print(e)
raise Exception("An unexpected error occoured")
return token
def retrieve_user(user_token):
token = _decode_apple_user_token(user_token)
apple_user = AppleUser(token["sub"], token.get("email", None))
return apple_user
@pythonwood
Copy link

pyjwt >= 2.0 diff from pyjwt == 1.7.1 options={"verify_exp": False}, algorithms=["RS256"],

change log

.. code:: python

import jwt
from jwt import PyJWKClient

token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA"
kid = "NEE1QURBOTM4MzI5RkFDNTYxOTU1MDg2ODgwQ0UzMTk1QjYyRkRFQw"
url = "https://dev-87evx9ru.auth0.com/.well-known/jwks.json"

jwks_client = PyJWKClient(url)
signing_key = jwks_client.get_signing_key_from_jwt(token)

data = jwt.decode(
    token,
    signing_key.key,
    algorithms=["RS256"],
    audience="https://expenses-api",
    options={"verify_exp": False},
)
print(data)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment