Install & Compatibility
Where this runs
tested against v22.0.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.000s · 39.9MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 3.3s · import 0.000s · 41MB
39MB installed
● package 39MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
JWTAuthVerifier
✓ from atlassian_jwt_auth import JWTAuthVerifier
✗ from atlassian_jwt_auth import AsymmetricSigningRequestAuthentication
create_signer
✓ from atlassian_jwt_auth import create_signer
HTTPSPublicKeyRetriever
✓ from atlassian_jwt_auth import HTTPSPublicKeyRetriever
This quickstart demonstrates how to use `AsymmetricSigningRequestAuthentication` to create a JWT for authenticating requests to an Atlassian instance. It initializes the authentication provider with your client key, key ID, private key, and add-on base URL, then generates a JWT to be included in the `Authorization` header of an HTTP request. This example includes a placeholder `qsh` (Query String Hash) which is critical in real Atlassian Connect applications and must be correctly calculated based on the target URL and query parameters. For demonstration purposes, it also includes a mechanism to generate a dummy private key if one doesn't exist, though a real key is required for actual authentication.
import os
import time
import requests
from atlassian_jwt_auth import AsymmetricSigningRequestAuthentication
# --- Configuration (replace with your actual values) ---
# Your Atlassian product's client key (usually from a descriptor or Atlassian Connect setup)
ATLASSIAN_CLIENT_KEY = os.environ.get('ATLASSIAN_CLIENT_KEY', 'your-client-key')
# Your Add-on's base URL (e.g., 'https://your-app.atlassian.net')
ADDON_BASE_URL = os.environ.get('ADDON_BASE_URL', 'https://your-addon.example.com')
# Path to your private key file (PEM format)
PRIVATE_KEY_PATH = os.environ.get('PRIVATE_KEY_PATH', 'path/to/your/private_key.pem')
# Your 'kid' (Key ID) for the private key
KEY_ID = os.environ.get('KEY_ID', 'your-key-id')
# Atlassian instance base URL you are communicating with (e.g., 'https://your-instance.atlassian.net')
ATLASSIAN_BASE_URL = os.environ.get('ATLASSIAN_BASE_URL', 'https://your-atlassian-instance.net')
# Ensure dummy values are not used in production
if 'your-' in ATLASSIAN_CLIENT_KEY or 'your-addon' in ADDON_BASE_URL or 'path/to/your/' in PRIVATE_KEY_PATH:
print("WARNING: Using dummy configuration values. Please set actual environment variables or hardcoded values.")
# For a runnable example, let's create a dummy key file if it doesn't exist
if not os.path.exists(PRIVATE_KEY_PATH):
try:
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
with open(PRIVATE_KEY_PATH, 'wb') as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
))
print(f"Dummy private key generated at {PRIVATE_KEY_PATH}")
except ImportError:
print("Cannot generate dummy key: cryptography not fully installed or missing. Please provide a real key.")
exit(1)
try:
with open(PRIVATE_KEY_PATH, 'rb') as key_file:
private_key_bytes = key_file.read()
# 1. Initialize the authentication provider
auth_provider = AsymmetricSigningRequestAuthentication(
client_key=ATLASSIAN_CLIENT_KEY,
key_id=KEY_ID,
private_key_pem=private_key_bytes,
base_url=ADDON_BASE_URL
)
# 2. Define the HTTP method and request URL
method = 'GET'
target_url_path = '/rest/api/latest/myself'
canonical_path = ADDON_BASE_URL + target_url_path
# 3. Create a JWT token for the request
# 'uri' is the canonical path of the request being made to the Atlassian host
# 'qsh' (Query String Hash) is typically generated by Atlassian Connect frameworks.
# For simple cases without query params, you might pass an empty string or rely on framework behavior.
# This example assumes a basic GET request with no query parameters.
# In a real app, 'qsh' is crucial and typically provided by the Atlassian Connect lifecycle.
# For a GET request with no query params, qsh is calculated on canonical path without query.
# For this example, we'll use a placeholder 'qsh'. Real applications should calculate this correctly.
# You might need to use `atlassian_jwt_auth.url_utils.create_canonical_query_string()`
# and `atlassian_jwt_auth.url_utils.create_query_string_hash()` to generate a proper qsh.
# For this quickstart, we'll demonstrate the signing process assuming a qsh can be generated/provided.
# A simple placeholder for qsh for demonstration. In real Atlassian Connect apps, this is vital.
qsh_value = 'some-pre-calculated-qsh' # REPLACE WITH ACTUAL QSH CALCULATION IF QUERY PARAMS EXIST
jwt_token = auth_provider.create_asymmetric_jwt(
method=method,
uri=target_url_path,
qsh=qsh_value,
token_lifetime_seconds=300 # Token valid for 5 minutes
)
# 4. Make an authenticated request using the JWT in the Authorization header
headers = {
'Authorization': f'JWT {jwt_token}',
'Accept': 'application/json'
}
print(f"Generated JWT: {jwt_token}")
print(f"Making request to {ATLASSIAN_BASE_URL}{target_url_path}")
# This part requires a real Atlassian instance to verify
# response = requests.get(f'{ATLASSIAN_BASE_URL}{target_url_path}', headers=headers)
# print(f"Response status: {response.status_code}")
# print(f"Response body: {response.json()}")
print("Request demonstration complete. Uncomment the 'requests.get' line to make a real call.")
print("Remember to replace placeholder configuration and qsh calculation with real values.")
except FileNotFoundError:
print(f"Error: Private key file not found at {PRIVATE_KEY_PATH}. Please ensure it exists and is accessible.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
Upgrade
Version history
22.0.1latest on PyPI · released May 21, 2026
Audit
Dependencies
pyjwtrequiredCore library for JWT encoding and decoding. Requires `[crypto]` extra for advanced algorithms.
cryptographyrequiredProvides cryptographic primitives for JWT signing and verification, used by PyJWT.
requestsrequiredUsed internally for HTTP requests, e.g., fetching public keys for verification.