JWT Login & Authentication

Crunchyroll Downloader โ€” Practical Scripting
Course 1 ยท Chapter 3 ยท JWT Login & Authentication

๐Ÿ” JWT Login & Authentication

Learn how to authenticate with Crunchyroll using email/password, receive a JWT token, cache it for reuse, and handle token expiration. This is the core of JWT-based API authentication.

๐Ÿ”‘ The Login Flow

import requests
import json
from pathlib import Path
from datetime import datetime

def login(config) -> str:
    """Login to Crunchyroll and get JWT token."""

    url = f"{config.api_base}/auth/v1/authenticate"

    payload = {
        "username": config.email,
        "password": config.password,
        "grant_type": "password"
    }

    try:
        # POST request to login endpoint
        response = requests.post(url, json=payload, timeout=10)

        if response.status_code != 200:
            print(f"โŒ Login failed: {response.status_code}")
            print(response.json())
            return None

        data = response.json()
        token = data.get('access_token')

        if not token:
            print("โŒ No token in response")
            return None

        print("โœ… Login successful!")
        return token

    except Exception as e:
        print(f"โŒ Login error: {e}")
        return None

๐Ÿ’พ Caching the Token

def save_token(token: str, cache_file: str):
    """Save token to file for reuse."""
    data = {
        "token": token,
        "timestamp": datetime.now().isoformat()
    }
    with open(cache_file, 'w') as f:
        json.dump(data, f)
    print(f"โœ… Token cached to {cache_file}")

def load_cached_token(cache_file: str) -> str:
    """Load cached token if it exists."""
    if not Path(cache_file).exists():
        return None

    try:
        with open(cache_file, 'r') as f:
            data = json.load(f)
            return data.get("token")
    except:
        return None

๐Ÿ“ Using the Token in Requests

def get_with_token(url: str, token: str) -> dict:
    """Make GET request with JWT token."""

    headers = {
        "Authorization": f"Bearer {token}",
        "User-Agent": "Mozilla/5.0"
    }

    try:
        response = requests.get(url, headers=headers, timeout=10)

        if response.status_code == 401:
            print("โŒ Token expired or invalid")
            return None

        if response.status_code == 200:
            return response.json()

        print(f"โŒ Request failed: {response.status_code}")
        return None

    except Exception as e:
        print(f"โŒ Error: {e}")
        return None

๐Ÿ’ป Coding Challenges

Challenge 1: Implement Login

Create login() function that authenticates with Crunchyroll and returns JWT token.

Challenge 2: Token Caching

Implement save_token() and load_cached_token() to avoid re-logging in.

Challenge 3: Authenticated Requests

Create get_with_token() that includes JWT in Authorization header.