What is PyJWT?
PyJWT is a Python library designed for creating, parsing, and validating JSON Web Tokens (JWT). JWT is a compact, self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. PyJWT simplifies the implementation of JWT in Python applications, providing a robust set of features for token-based authentication and data transmission.
Installing PyJWT
To begin using PyJWT, you'll need to install it first. The simplest way to install PyJWT is using pip:
pip install PyJWT
Once installed, you can import the library into your Python scripts:
import jwt
Core JWT Concepts
Before diving into implementation, it's essential to understand the fundamental components of JWT:
- **Token**: The encoded string that carries information between parties.
- **Header**: Contains metadata about the token, including the signing algorithm and token type.
- **Payload**: Contains the claims, which are statements about an entity (typically a user) and additional data.
- **Signature**: The cryptographic signature used to verify the token's integrity and authenticity.
- **Algorithm**: The cryptographic method used to sign and verify the token, such as HS256, RS256, etc.
Creating JWT Tokens
Here's how you can create a JWT token using PyJWT:
import jwt
import datetime
# Define payload data
payload_data = {
'user_id': 42,
'username': 'john_doe',
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}
# Generate JWT token
secret_key = 'your-secret-key-here'
token = jwt.encode(payload_data, secret_key, algorithm='HS256')
print(token)
This example creates a token with user information and sets an expiration time one hour from now.
Parsing JWT Tokens
To decode a JWT token without verifying its signature:
import jwt
# Token received from client
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo0MiwidXNlcm5hbWUiOiJqb2huX2RvZSIsImV4cCI6MTYwODkxNzkwMH0.abcdef123456"
# Decode token without verification
decoded = jwt.decode(token, options={"verify_signature": False})
print(decoded)
Verifying JWT Tokens
For security-critical applications, you should verify the token signature:
import jwt
# Token received from client
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo0MiwidXNlcm5hbWUiOiJqb2huX2RvZSIsImV4cCI6MTYwODkxNzkwMH0.abcdef123456"
# Secret key used for signing
secret_key = 'your-secret-key-here'
try:
# Verify and decode token
decoded = jwt.decode(token, secret_key, algorithms=['HS256'])
print("Token is valid:", decoded)
except jwt.ExpiredSignatureError:
print("Token has expired")
except jwt.InvalidTokenError:
print("Invalid token")
Advanced Features and Use Cases
Custom Expiration Handling
PyJWT allows for flexible expiration handling:
import jwt
import datetime
# Create token with custom expiration
payload = {
'user_id': 42,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
# Check expiration manually
decoded = jwt.decode(token, options={"verify_signature": False})
if decoded['exp'] < datetime.datetime.utcnow().timestamp():
print("Token has expired")
else:
print("Token is still valid")
Selecting Encryption Algorithms
PyJWT supports various algorithms for signing tokens:
import jwt
# Using HMAC with SHA-256 (HS256)
payload = {'user_id': 42}
token_hs256 = jwt.encode(payload, 'secret', algorithm='HS256')
# Using RSA with SHA-256 (RS256)
# Note: You would need to generate/load your RSA keys
private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...your private key here...
-----END RSA PRIVATE KEY-----"""
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...your public key here...
-----END PUBLIC KEY-----"""
token_rs256 = jwt.encode(payload, private_key, algorithm='RS256')
# Verify with public key
decoded = jwt.decode(token_rs256, public_key, algorithms=['RS256'])
Refresh Tokens
Implementing refresh tokens for maintaining user sessions:
import jwt
import datetime
def generate_tokens(user_id):
"""Generate access and refresh tokens for a user"""
# Access token with short expiration
access_payload = {
'user_id': user_id,
'type': 'access',
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
}
access_token = jwt.encode(access_payload, 'access-secret', algorithm='HS256')
# Refresh token with longer expiration
refresh_payload = {
'user_id': user_id,
'type': 'refresh',
'exp': datetime.datetime.utcnow() + datetime.timedelta(days=7)
}
refresh_token = jwt.encode(refresh_payload, 'refresh-secret', algorithm='HS256')
return access_token, refresh_token
def refresh_access_token(refresh_token):
"""Generate a new access token using a valid refresh token"""
try:
# Verify refresh token
payload = jwt.decode(refresh_token, 'refresh-secret', algorithms=['HS256'])
# Check if it's a refresh token
if payload.get('type') != 'refresh':
raise jwt.InvalidTokenError("Invalid token type")
# Generate new access token
access_payload = {
'user_id': payload['user_id'],
'type': 'access',
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
}
return jwt.encode(access_payload, 'access-secret', algorithm='HS256')
except jwt.ExpiredSignatureError:
raise Exception("Refresh token has expired")
except jwt.InvalidTokenError:
raise Exception("Invalid refresh token")