CognitoJWT
CognitoJWT is a Python library designed to decode and verify Amazon Cognito JWT (JSON Web Token) tokens. It simplifies the process of validating ID and Access tokens issued by AWS Cognito User Pools, ensuring their integrity and authenticity. The library supports both synchronous (using `requests`) and asynchronous (using `aiohttp`) modes. While the last release was in 2021 (v1.4.1), its GitHub repository is archived, indicating a maintenance-only status with no active feature development. [2, 14]
Common errors
-
Token verification failed: Token is expired
cause The JWT token's 'exp' (expiration) claim indicates it has passed its valid timestamp.fixThis is expected behavior for expired tokens. Your application should handle this by prompting the user for re-authentication or using a valid refresh token to obtain new ID and access tokens if applicable. Ensure your system clock is synchronized. -
Token verification failed: Invalid signature
cause The token's signature cannot be verified using the public keys obtained from the Cognito JWKS endpoint, likely due to stale or incorrect JWKS keys, or a tampered token.fixEnsure your application can successfully fetch the latest JWKS file from `https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json`. If caching JWKS, clear the cache and re-fetch. Verify that the `region` and `userpool_id` provided to `cognitojwt.decode` are correct. [4] -
Token verification failed: Invalid 'aud' claim
cause The 'aud' (audience) claim in the token's payload does not match the `app_client_id` provided during verification.fixEnsure the `app_client_id` passed to `cognitojwt.decode` or `cognitojwt.decode_async` is the correct client ID that the token was issued for. If your application supports multiple client IDs, pass a list or tuple of allowed client IDs. [14] -
Token verification failed: Invalid 'iss' claim
cause The 'iss' (issuer) claim in the token's payload does not match the expected Cognito User Pool issuer URL.fixVerify that the `region` and `userpool_id` passed to `cognitojwt.decode` or `cognitojwt.decode_async` correctly correspond to the Cognito User Pool that issued the token. The expected issuer format is `https://cognito-idp.{region}.amazonaws.com/{userPoolId}`. [1]
Warnings
- gotcha The cognitojwt GitHub repository is archived, meaning it is no longer under active development for new features. While functional, consider this when starting new projects or evaluating long-term maintenance. [2]
- breaking Do not hardcode Cognito public keys. AWS frequently rotates its signing keys. Always fetch the JSON Web Key Set (JWKS) from the provided Cognito endpoint to ensure signature verification uses the correct, up-to-date keys. [1]
- gotcha Ensure proper validation of the `token_use` claim. Cognito issues both ID tokens (for user identity) and Access tokens (for API authorization), and mixing them up can lead to security vulnerabilities or validation failures. [1, 4]
- gotcha Be mindful of clock skew between your server and the Cognito service. A slight time difference can cause valid tokens to fail expiration checks. [1]
Install
-
pip install cognitojwt[sync] -
pip install cognitojwt[async]
Imports
- cognitojwt
import cognitojwt
Quickstart
import cognitojwt
import os
# Replace with your actual Cognito details or load from environment variables
id_token = os.environ.get('COGNITO_ID_TOKEN', 'YOUR_COGNITO_ID_TOKEN_HERE') # Example token, should come from authentication flow
region = os.environ.get('AWS_REGION', 'us-east-1')
userpool_id = os.environ.get('COGNITO_USERPOOL_ID', 'us-east-1_XXXXXXXXX')
app_client_id = os.environ.get('COGNITO_APP_CLIENT_ID', 'YOUR_APP_CLIENT_ID') # Optional, but highly recommended for 'aud' claim verification
try:
# Synchronous mode example
verified_claims: dict = cognitojwt.decode(
id_token,
region,
userpool_id,
app_client_id=app_client_id, # Optional: verifies the 'aud' claim matches your app client ID
testmode=False # Set to True to disable token expiration check for testing only
)
print("Token successfully verified (sync mode):")
print(verified_claims)
# Asynchronous mode example (requires an async context, e.g., FastAPI, Sanic, or standalone with asyncio.run)
# import asyncio
# async def main():
# verified_claims_async: dict = await cognitojwt.decode_async(
# id_token,
# region,
# userpool_id,
# app_client_id=app_client_id,
# testmode=False
# )
# print("Token successfully verified (async mode):")
# print(verified_claims_async)
# asyncio.run(main())
except cognitojwt.exceptions.CognitoJWTException as e:
print(f"Token verification failed: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")