Module for generating and verifying JSON Web Tokens
npx @tessl/cli install tessl/pypi-python-jwt@3.3.00
# python-jwt
1
2
python-jwt is a comprehensive Python library for generating and verifying JSON Web Tokens (JWT). It provides secure token generation and verification for authentication and authorization systems with support for multiple signature algorithms including RSA, PSS, ECDSA, HMAC, EdDSA, and none. The library leverages jwcrypto for cryptographic operations and includes built-in security features to prevent common JWT vulnerabilities.
3
4
## Package Information
5
6
- **Package Name**: python_jwt
7
- **Package Type**: pypi
8
- **Language**: Python
9
- **Installation**: `pip install python_jwt`
10
11
## Core Imports
12
13
```python
14
import python_jwt as jwt
15
```
16
17
Alternative direct imports:
18
```python
19
from python_jwt import generate_jwt, verify_jwt, process_jwt
20
```
21
22
## Basic Usage
23
24
```python
25
import python_jwt as jwt
26
import jwcrypto.jwk as jwk
27
from datetime import timedelta
28
29
# Generate a key for signing
30
key = jwk.JWK.generate(kty='RSA', size=2048)
31
32
# Create JWT claims
33
payload = {'user_id': 123, 'role': 'admin'}
34
35
# Generate a JWT token
36
token = jwt.generate_jwt(payload, key, 'PS256', timedelta(minutes=60))
37
38
# Verify the JWT token
39
header, claims = jwt.verify_jwt(token, key, ['PS256'])
40
41
# Access the claims
42
print(f"User ID: {claims['user_id']}")
43
print(f"Role: {claims['role']}")
44
```
45
46
## Capabilities
47
48
### Token Generation
49
50
Generate JSON Web Tokens with customizable claims, expiration, and signature algorithms.
51
52
```python { .api }
53
def generate_jwt(claims, priv_key=None, algorithm='PS512', lifetime=None,
54
expires=None, not_before=None, jti_size=16, other_headers=None):
55
"""
56
Generate a JSON Web Token.
57
58
Parameters:
59
- claims (dict): The claims you want included in the signature
60
- priv_key (jwcrypto.jwk.JWK, optional): The private key to be used to sign the token.
61
If None, token will be returned with empty signature and algorithm will be 'none'
62
- algorithm (str): The algorithm to use for generating the signature.
63
Supported: RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512,
64
ES256K, HS256, HS384, HS512, EdDSA, none. Default: 'PS512'
65
- lifetime (datetime.timedelta, optional): How long the token is valid for
66
- expires (datetime.datetime, optional): When the token expires (alternative to lifetime)
67
- not_before (datetime.datetime, optional): When the token is valid from.
68
Defaults to current time if None
69
- jti_size (int): Size in bytes of the unique token ID. Default: 16.
70
Specify 0 or None to omit JTI from token
71
- other_headers (dict, optional): Additional headers (cannot override 'typ' or 'alg')
72
73
Returns:
74
str: The JSON Web Token with header, claims, and cryptographic signature
75
76
Raises:
77
ValueError: If other_headers contains 'typ' or 'alg' headers
78
79
Note:
80
The following claims are automatically added per JWT spec:
81
- exp (IntDate): UTC expiry date and time in seconds since epoch
82
- iat (IntDate): UTC date and time when token was generated
83
- nbf (IntDate): UTC valid-from date and time
84
- jti (str): Unique identifier for the token (if jti_size > 0)
85
"""
86
```
87
88
#### Usage Examples
89
90
Basic token generation:
91
```python
92
import python_jwt as jwt
93
import jwcrypto.jwk as jwk
94
from datetime import timedelta
95
96
key = jwk.JWK.generate(kty='RSA', size=2048)
97
claims = {'user': 'alice', 'permissions': ['read', 'write']}
98
token = jwt.generate_jwt(claims, key, 'RS256', timedelta(hours=1))
99
```
100
101
Token with custom expiration:
102
```python
103
from datetime import datetime, timedelta
104
105
expires_at = datetime.utcnow() + timedelta(days=7)
106
token = jwt.generate_jwt(claims, key, 'PS256', expires=expires_at)
107
```
108
109
Unsigned token (algorithm 'none'):
110
```python
111
# For testing or when signature verification is handled elsewhere
112
token = jwt.generate_jwt(claims, None, 'none')
113
```
114
115
Token with additional headers:
116
```python
117
extra_headers = {'kid': 'key-123', 'custom': 'value'}
118
token = jwt.generate_jwt(claims, key, 'ES256', timedelta(minutes=30),
119
other_headers=extra_headers)
120
```
121
122
### Token Verification
123
124
Verify and decode JSON Web Tokens with comprehensive security checks.
125
126
```python { .api }
127
def verify_jwt(jwt, pub_key=None, allowed_algs=None, iat_skew=timedelta(),
128
checks_optional=False, ignore_not_implemented=False):
129
"""
130
Verify a JSON Web Token.
131
132
Parameters:
133
- jwt (str): The JSON Web Token to verify
134
- pub_key (jwcrypto.jwk.JWK, optional): The public key to be used to verify the token.
135
If None and 'none' in allowed_algs, signature will not be verified
136
- allowed_algs (list, optional): Algorithms expected to be used to sign the token.
137
Uses 'in' operator to test membership. None means empty list
138
- iat_skew (datetime.timedelta): Amount of leeway between issuer's and verifier's
139
clock when verifying token was generated in the past. Default: no leeway
140
- checks_optional (bool): If False, token must contain 'typ' header and
141
'iat', 'nbf', 'exp' claim properties. Default: False
142
- ignore_not_implemented (bool): If False, token must not contain 'jku',
143
'jwk', 'x5u', 'x5c', or 'x5t' header properties. Default: False
144
145
Returns:
146
tuple: (header, claims) if token was verified successfully
147
148
Raises:
149
Various exceptions: If token failed to verify
150
151
Verification Tests:
152
- Header must contain 'alg' property with value in allowed_algs
153
- Signature must verify using pub_key (unless algorithm is 'none' and 'none' in allowed_algs)
154
- If corresponding property is present or checks_optional is False:
155
- Header must contain 'typ' property with value 'JWT'
156
- Claims must contain 'iat' property representing date in past (with iat_skew tolerance)
157
- Claims must contain 'nbf' property representing date in the past
158
- Claims must contain 'exp' property representing date in the future
159
"""
160
```
161
162
#### Usage Examples
163
164
Basic token verification:
165
```python
166
try:
167
header, claims = jwt.verify_jwt(token, public_key, ['RS256'])
168
print(f"Token valid. User: {claims.get('user')}")
169
except Exception as e:
170
print(f"Token verification failed: {e}")
171
```
172
173
Verification with multiple allowed algorithms:
174
```python
175
# Allow multiple signature algorithms
176
header, claims = jwt.verify_jwt(token, key, ['RS256', 'PS256', 'ES256'])
177
```
178
179
Verification with clock skew tolerance:
180
```python
181
from datetime import timedelta
182
183
# Allow 5 minutes of clock skew
184
header, claims = jwt.verify_jwt(token, key, ['PS512'],
185
iat_skew=timedelta(minutes=5))
186
```
187
188
Verification with optional checks:
189
```python
190
# Skip strict validation of standard claims
191
header, claims = jwt.verify_jwt(token, key, ['HS256'], checks_optional=True)
192
```
193
194
### Token Processing
195
196
Process JWT tokens without verification to inspect headers and claims.
197
198
```python { .api }
199
def process_jwt(jwt):
200
"""
201
Process a JSON Web Token without verifying it.
202
203
Call this before verify_jwt if you need access to the header or claims
204
in the token before verifying it. For example, the claims might identify
205
the issuer such that you can retrieve the appropriate public key.
206
207
Parameters:
208
- jwt (str): The JSON Web Token to process
209
210
Returns:
211
tuple: (header, claims)
212
213
Raises:
214
_JWTError: If JWT format is invalid
215
"""
216
```
217
218
#### Usage Examples
219
220
Inspect token before verification:
221
```python
222
# Get issuer from claims to determine which key to use
223
header, claims = jwt.process_jwt(token)
224
issuer = claims.get('iss')
225
226
# Select appropriate key based on issuer
227
if issuer == 'service-a':
228
verification_key = service_a_key
229
elif issuer == 'service-b':
230
verification_key = service_b_key
231
else:
232
raise ValueError(f"Unknown issuer: {issuer}")
233
234
# Now verify with appropriate key
235
header, verified_claims = jwt.verify_jwt(token, verification_key, ['RS256'])
236
```
237
238
Debug token contents:
239
```python
240
try:
241
header, claims = jwt.process_jwt(token)
242
print(f"Algorithm: {header.get('alg')}")
243
print(f"Claims: {claims}")
244
except Exception as e:
245
print(f"Invalid JWT format: {e}")
246
```
247
248
## Supported Algorithms
249
250
The library supports the following JWT signature algorithms:
251
252
- **RSA**: RS256, RS384, RS512 - RSA PKCS#1 signature with SHA-256/384/512
253
- **PSS**: PS256, PS384, PS512 - RSA PSS signature with SHA-256/384/512
254
- **ECDSA**: ES256, ES384, ES512, ES256K - ECDSA signature with various curves
255
- **HMAC**: HS256, HS384, HS512 - HMAC with SHA-256/384/512
256
- **EdDSA**: EdDSA - Edwards-curve Digital Signature Algorithm
257
- **None**: none - Unsigned tokens (use with caution)
258
259
## Standard JWT Claims
260
261
The library automatically handles these standard JWT claims:
262
263
- **exp** (expiration time): Automatically added when `lifetime` or `expires` specified
264
- **iat** (issued at): Automatically added during token generation
265
- **nbf** (not before): Added based on `not_before` parameter or current time
266
- **jti** (JWT ID): Added if `jti_size` > 0 (default 16 bytes, base64url encoded)
267
268
## Key Management Integration
269
270
python-jwt integrates with jwcrypto for key management:
271
272
```python
273
import jwcrypto.jwk as jwk
274
275
# Generate keys
276
rsa_key = jwk.JWK.generate(kty='RSA', size=2048)
277
ec_key = jwk.JWK.generate(kty='EC', curve='P-256')
278
279
# Load from PEM
280
private_pem = "-----BEGIN PRIVATE KEY-----\n..."
281
private_key = jwk.JWK.from_pem(private_pem.encode())
282
283
public_pem = "-----BEGIN PUBLIC KEY-----\n..."
284
public_key = jwk.JWK.from_pem(public_pem.encode())
285
286
# Export to PEM
287
private_pem = rsa_key.export_to_pem(private_key=True, password=None)
288
public_pem = rsa_key.export_to_pem(private_key=False)
289
```
290
291
## Error Handling
292
293
The library raises various exceptions during token operations:
294
295
- **ValueError**: For invalid parameters (e.g., conflicting headers in `other_headers`)
296
- **jwcrypto exceptions**: For cryptographic failures during signing/verification
297
- **_JWTError**: Internal JWT-specific validation failures (format, claims, algorithms)
298
299
```python { .api }
300
class _JWTError(Exception):
301
"""
302
Exception raised for JWT-specific validation failures.
303
304
This is a private exception class used internally by python-jwt
305
for JWT format validation, claims verification, and algorithm checks.
306
Applications should catch general Exception or specific jwcrypto
307
exceptions rather than relying on this internal exception type.
308
"""
309
```
310
311
Common error scenarios:
312
```python
313
try:
314
token = jwt.generate_jwt(claims, key, 'RS256', timedelta(hours=1))
315
header, claims = jwt.verify_jwt(token, key, ['RS256'])
316
except ValueError as e:
317
print(f"Invalid parameters: {e}")
318
except Exception as e:
319
print(f"JWT operation failed: {e}")
320
```
321
322
## Security Considerations
323
324
- **Algorithm specification**: Always specify `allowed_algs` in verification to prevent algorithm confusion attacks
325
- **Key management**: Use appropriate key sizes (RSA 2048+ bits, EC P-256+ curves)
326
- **Clock skew**: Consider `iat_skew` parameter for distributed systems
327
- **Token lifetime**: Use reasonable expiration times to limit exposure
328
- **Signature verification**: Never skip signature verification in production (avoid 'none' algorithm)
329
- **Unique identifiers**: Use `jti` parameter to detect replay attacks when needed