Python port for Canva plugin verify JWT, you can find the original canva article with js here: https://www.canva.dev/docs/apps/verifying-jwts/
Code licensed under MIT
import jwt
import json
import time
import requests
from jwcrypto import jwk
from typing import Dict, Any
CACHE_EXPIRY_SECONDS = 60 * 60 # 60 minutes
jwks_cache = {}
jwks_timestamp = 0
def fetch_canva_jwks(app_id: str) -> Dict[str, Any]:
global jwks_cache, jwks_timestamp
current_time = time.time()
# Check if the cache is expired
if jwks_cache and (current_time - jwks_timestamp) < CACHE_EXPIRY_SECONDS:
return jwks_cache
# Fetch the JWKS
response = requests.get(f"https://api.canva.com/rest/v1/apps/{app_id}/jwks")
response.raise_for_status() # Raise an error for bad responses
jwks_cache = response.json() # Cache the JWKS
jwks_timestamp = current_time
return jwks_cache
def get_active_public_key(app_id: str, token: str) -> str:
decoded = jwt.get_unverified_header(token) # Get the JWT header
kid = decoded['kid'] # Extract the kid property
# Fetch the JWKS
jwks = fetch_canva_jwks(app_id)
# Find the active public key
for key in jwks['keys']:
if key['kid'] == kid:
public_key = jwk.JWK.from_json(json.dumps(key)) # Convert to JWK
return public_key.export_to_pem() # Export as PEM format
raise Exception("Public key not found for the provided kid.")
def verify_jwt(app_id: str, token: str) -> Dict[str, Any]:
public_key = get_active_public_key(app_id, token) # Get the active public key
try:
verified_token = jwt.decode(token, public_key, algorithms=["RS256"], audience=app_id) # Verify the token
return verified_token
except jwt.ExpiredSignatureError:
raise Exception("Token has expired.")
except jwt.InvalidTokenError:
raise Exception("Invalid token.")
token = "" # this token should be retrieved from canva using auth.getCanvaUserToken or for design, design specific api
app_id = "" # this is your app id
print(verify_jwt(app_id, token))
Print will print the object with userid, brandid aud etc.