Skip to content

Instantly share code, notes, and snippets.

@PaulleDemon
Created October 17, 2024 06:20
Show Gist options
  • Save PaulleDemon/e1f344e8061c5a736ed202bdc5b38e62 to your computer and use it in GitHub Desktop.
Save PaulleDemon/e1f344e8061c5a736ed202bdc5b38e62 to your computer and use it in GitHub Desktop.
A port for

Canva Verify JWT - Python

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.

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