Registry / auth-security / atlassian-jwt-auth

atlassian-jwt-auth

JSON →
library22.0.1pypypi✓ verified 83d ago

Atlassian JWT Auth provides a Python implementation of the Atlassian Service to Service Authentication specification, wrapping the PyJWT library. It enables applications to securely sign and verify JSON Web Tokens (JWTs) for communication with Atlassian products using both symmetric and asymmetric key pairs. The current version is 22.0.0, with major releases typically occurring annually or bi-annually.

pip install atlassian-jwt-auth
INSTALL
IMPORT
SIG · ATLASSIAN-JWT-AUTH
A
atlassian-jwt-auth
auth-securitypythonv22.0.1
Install
3.3s avg
Import
Disk
39MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
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
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.000s · 39.9MB
glibc
py 3.103.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}")
Debug
Known issues
breakingPython 2 support was dropped in version 18.0.0. Projects still on Python 2 must either remain on an older version of `atlassian-jwt-auth` or migrate to Python 3.
fix
Upgrade to Python 3 (3.6+ recommended).
affects: >=18.0.0
breakingThe constructor for `SigningRequestAuthentication` removed the `signature_algorithm` parameter in version 15.0.0. The algorithm is now inferred from the key material.
fix
Remove the `signature_algorithm` argument from `SigningRequestAuthentication` instantiations. Ensure your key material is correctly formatted so the algorithm can be inferred.
affects: >=15.0.0
breakingThe function `create_asap_jwt` was renamed to `create_oauth_2_bearer_token` in version 16.0.0 for better clarity regarding its specific use case (OAuth 2.0 bearer tokens).
fix
Update calls from `create_asap_jwt(...)` to `create_oauth_2_bearer_token(...)`.
affects: >=16.0.0
gotchaVersion 22.0.0 (and newer) requires `PyJWT>=2.0.0` and `cryptography>=3.3.1`. Using older versions of these dependencies, especially `PyJWT<2.0.0`, will lead to import errors or runtime issues due to API changes in PyJWT.
fix
Ensure your project's `pyjwt` and `cryptography` dependencies are up-to-date and compatible with `atlassian-jwt-auth` by running `pip install --upgrade atlassian-jwt-auth 'pyjwt[crypto]' cryptography`.
affects: >=22.0.0
gotchaIncorrect `qsh` (Query String Hash) calculation for requests to Atlassian products will result in 'Invalid JWT signature' or 'Authentication Failed' errors, even if the token itself is well-formed. The `qsh` is critical for Atlassian Connect authentication.
fix
Ensure `qsh` is calculated precisely according to Atlassian's canonical URL specification. This often involves using helper functions like `atlassian_jwt_auth.url_utils.create_canonical_query_string` and `create_query_string_hash`.
affects: All versions
gotchaTime synchronization issues (clock skew) between your application and the Atlassian instance can cause JWTs to be rejected with 'token expired' errors, even if they appear valid.
fix
Synchronize your server's clock using NTP. Use a reasonable `token_lifetime_seconds` (e.g., 300 seconds) and ensure `iat` (issued at) and `exp` (expiration) claims are correctly generated relative to a synced clock. PyJWT generally handles `nbf` (not before) and `exp` with a configurable leeway.
affects: All versions
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.
Agent activity
29 hits · last 30 days
node
24
OpenAI (training)
1
Resources