0
# JWT Operations
1
2
High-level JSON Web Token functionality providing comprehensive support for encoding, decoding, and validating JWT tokens with automatic claim validation, flexible key handling, and extensive configuration options.
3
4
## Capabilities
5
6
### Token Encoding
7
8
Creates JWT tokens from claims dictionaries with support for various signing algorithms and additional headers.
9
10
```python { .api }
11
def encode(claims, key, algorithm='HS256', headers=None, access_token=None):
12
"""
13
Encodes a claims set and returns a JWT string.
14
15
Args:
16
claims (dict): A claims set to sign. Can include standard claims
17
(iss, sub, aud, exp, nbf, iat, jti) and custom claims
18
key (str or bytes or dict): The key to use for signing. Supports:
19
- String secrets for HMAC algorithms
20
- RSA/EC private keys in PEM format
21
- JWK dictionaries
22
algorithm (str): The algorithm to use for signing. Defaults to 'HS256'.
23
Supported algorithms: HS256, HS384, HS512, RS256, RS384, RS512,
24
ES256, ES384, ES512
25
headers (dict, optional): Additional headers to include in the JWT header.
26
Will override default headers with the same keys
27
access_token (str, optional): If present, the 'at_hash' claim will be
28
calculated and added to the claims
29
30
Returns:
31
str: The JWT token string in the format header.payload.signature
32
33
Raises:
34
JWTError: If there is an error encoding the claims
35
"""
36
```
37
38
**Usage Examples:**
39
40
```python
41
from jose import jwt
42
from jose.constants import ALGORITHMS
43
44
# Basic HMAC signing
45
token = jwt.encode({'user': 'john', 'role': 'admin'}, 'secret', algorithm=ALGORITHMS.HS256)
46
47
# With expiration time
48
import time
49
claims = {
50
'user': 'jane',
51
'exp': int(time.time()) + 3600, # Expires in 1 hour
52
'iat': int(time.time()), # Issued now
53
'iss': 'my-app' # Issuer
54
}
55
token = jwt.encode(claims, 'secret')
56
57
# RSA signing with private key
58
rsa_private_key = """-----BEGIN PRIVATE KEY-----
59
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...
60
-----END PRIVATE KEY-----"""
61
62
token = jwt.encode({'user': 'alice'}, rsa_private_key, algorithm=ALGORITHMS.RS256)
63
64
# With additional headers
65
headers = {'kid': 'key-1', 'typ': 'JWT'}
66
token = jwt.encode({'user': 'bob'}, 'secret', headers=headers)
67
68
# With access token hash for OpenID Connect
69
access_token = 'SlAV32hkKG'
70
token = jwt.encode({'user': 'charlie'}, 'secret', access_token=access_token)
71
```
72
73
### Token Decoding and Verification
74
75
Decodes and verifies JWT tokens with comprehensive claim validation and flexible verification options.
76
77
```python { .api }
78
def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None):
79
"""
80
Decodes and verifies a JWT token.
81
82
Args:
83
token (str): The JWT token to decode
84
key (str or bytes or dict or list): The verification key(s). Supports:
85
- String secrets for HMAC algorithms
86
- RSA/EC public keys in PEM format
87
- JWK dictionaries
88
- List of keys to try multiple keys
89
algorithms (str or list): Allowed algorithms for verification. If None,
90
raises an error. Use specific algorithms like ['HS256'] for security
91
options (dict, optional): Verification options controlling which claims
92
to verify and validation behavior
93
audience (str, optional): Expected audience claim ('aud'). Token must
94
contain this exact audience value
95
issuer (str or list or tuple, optional): Expected issuer claim(s) ('iss').
96
Token issuer must match one of the provided values
97
subject (str, optional): Expected subject claim ('sub'). Token must
98
contain this exact subject value
99
access_token (str, optional): Access token for 'at_hash' verification
100
in OpenID Connect scenarios
101
102
Returns:
103
dict: The decoded payload claims
104
105
Raises:
106
JWTError: If the token is invalid or verification fails
107
ExpiredSignatureError: If the token has expired
108
JWTClaimsError: If claim validation fails
109
"""
110
```
111
112
**Verification Options:**
113
114
The `options` parameter accepts a dictionary with the following keys:
115
116
```python { .api }
117
# Default options
118
options = {
119
'verify_signature': True, # Verify the token signature
120
'verify_exp': True, # Verify expiration time claim
121
'verify_nbf': True, # Verify not before time claim
122
'verify_iat': True, # Verify issued at time claim
123
'verify_aud': True, # Verify audience claim
124
'verify_iss': True, # Verify issuer claim
125
'verify_sub': True, # Verify subject claim
126
'verify_jti': True, # Verify JWT ID claim
127
'require_exp': False, # Require exp claim to be present
128
'require_iat': False, # Require iat claim to be present
129
'require_nbf': False, # Require nbf claim to be present
130
'require_aud': False, # Require aud claim to be present
131
'require_iss': False, # Require iss claim to be present
132
'require_sub': False, # Require sub claim to be present
133
'require_jti': False, # Require jti claim to be present
134
'leeway': 0 # Leeway in seconds for time-based claims
135
}
136
```
137
138
**Usage Examples:**
139
140
```python
141
from jose import jwt
142
from jose.exceptions import ExpiredSignatureError, JWTError
143
from datetime import timedelta
144
145
# Basic verification
146
try:
147
claims = jwt.decode(token, 'secret', algorithms=['HS256'])
148
print(f"User: {claims['user']}")
149
except JWTError as e:
150
print(f"Token validation failed: {e}")
151
152
# Verification with audience and issuer
153
claims = jwt.decode(
154
token,
155
'secret',
156
algorithms=['HS256'],
157
audience='my-app',
158
issuer='trusted-issuer'
159
)
160
161
# Verification with leeway for clock skew
162
options = {'leeway': 30} # 30 seconds leeway
163
claims = jwt.decode(token, 'secret', algorithms=['HS256'], options=options)
164
165
# Skip signature verification (for debugging only)
166
options = {'verify_signature': False}
167
claims = jwt.decode(token, 'secret', algorithms=['HS256'], options=options)
168
169
# Require specific claims
170
options = {
171
'require_exp': True,
172
'require_iss': True,
173
'require_aud': True
174
}
175
claims = jwt.decode(token, 'secret', algorithms=['HS256'], options=options)
176
177
# Multiple key verification (JWK set scenario)
178
keys = [
179
{'kty': 'oct', 'k': 'key1'},
180
{'kty': 'oct', 'k': 'key2'},
181
'backup-secret'
182
]
183
claims = jwt.decode(token, keys, algorithms=['HS256'])
184
185
# RSA public key verification
186
rsa_public_key = """-----BEGIN PUBLIC KEY-----
187
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
188
-----END PUBLIC KEY-----"""
189
190
claims = jwt.decode(token, rsa_public_key, algorithms=['RS256'])
191
```
192
193
### Header and Claims Inspection
194
195
Retrieve JWT headers and claims without performing verification, useful for debugging and token inspection.
196
197
```python { .api }
198
def get_unverified_header(token):
199
"""
200
Get JWT header without verification.
201
202
Args:
203
token (str): The JWT token
204
205
Returns:
206
dict: The JWT header dictionary
207
208
Raises:
209
JWTError: If the token format is invalid
210
"""
211
212
def get_unverified_headers(token):
213
"""
214
Get JWT header without verification (alias for get_unverified_header).
215
216
Args:
217
token (str): The JWT token
218
219
Returns:
220
dict: The JWT header dictionary
221
222
Raises:
223
JWTError: If the token format is invalid
224
"""
225
226
def get_unverified_claims(token):
227
"""
228
Get JWT payload claims without verification.
229
230
Args:
231
token (str): The JWT token
232
233
Returns:
234
dict: The JWT payload claims dictionary
235
236
Raises:
237
JWTError: If the token format is invalid
238
"""
239
```
240
241
**Usage Examples:**
242
243
```python
244
# Inspect token header (useful for getting 'kid' for key selection)
245
header = jwt.get_unverified_header(token)
246
print(f"Algorithm: {header['alg']}")
247
print(f"Key ID: {header.get('kid')}")
248
249
# Inspect token claims (useful for debugging expired tokens)
250
claims = jwt.get_unverified_claims(token)
251
print(f"Issuer: {claims.get('iss')}")
252
print(f"Subject: {claims.get('sub')}")
253
print(f"Expires: {claims.get('exp')}")
254
255
# Conditional verification based on header
256
header = jwt.get_unverified_header(token)
257
if header['alg'] == 'HS256':
258
claims = jwt.decode(token, hmac_secret, algorithms=['HS256'])
259
elif header['alg'] == 'RS256':
260
claims = jwt.decode(token, rsa_public_key, algorithms=['RS256'])
261
```
262
263
## Standard JWT Claims
264
265
The JWT specification defines several standard claims:
266
267
```python { .api }
268
# Standard claims supported by python-jose
269
claims = {
270
'iss': 'issuer', # Issuer - who issued the token
271
'sub': 'subject', # Subject - who the token is about
272
'aud': 'audience', # Audience - who the token is intended for
273
'exp': 1234567890, # Expiration time (Unix timestamp)
274
'nbf': 1234567890, # Not before time (Unix timestamp)
275
'iat': 1234567890, # Issued at time (Unix timestamp)
276
'jti': 'unique-id', # JWT ID - unique identifier for the token
277
'at_hash': 'hash-value' # Access token hash (OpenID Connect)
278
}
279
```
280
281
## Error Handling
282
283
JWT operations can raise several specific exceptions:
284
285
```python { .api }
286
class JWTError(JOSEError):
287
"""Base exception for JWT-related errors."""
288
289
class JWTClaimsError(JWTError):
290
"""JWT claims validation failed."""
291
292
class ExpiredSignatureError(JWTError):
293
"""JWT token has expired."""
294
```
295
296
**Common Error Scenarios:**
297
298
```python
299
from jose import jwt
300
from jose.exceptions import JWTError, ExpiredSignatureError, JWTClaimsError
301
302
try:
303
claims = jwt.decode(token, key, algorithms=['HS256'], audience='my-app')
304
except ExpiredSignatureError:
305
# Token has expired (exp claim)
306
print("Token has expired")
307
except JWTClaimsError as e:
308
# Claims validation failed (aud, iss, sub, etc.)
309
print(f"Claims validation failed: {e}")
310
except JWTError as e:
311
# Other JWT errors (invalid format, signature, etc.)
312
print(f"JWT error: {e}")
313
```
314
315
## OpenID Connect Support
316
317
The library provides built-in support for OpenID Connect JWT features:
318
319
```python
320
# Access token hash calculation (at_hash claim)
321
access_token = 'SlAV32hkKG'
322
id_token = jwt.encode(
323
{'sub': '12345', 'aud': 'client-id'},
324
key,
325
access_token=access_token
326
)
327
328
# Verification includes at_hash validation
329
claims = jwt.decode(
330
id_token,
331
key,
332
algorithms=['HS256'],
333
access_token=access_token
334
)
335
```
336
337
## Best Practices
338
339
1. **Always specify algorithms**: Never use `algorithms=None` in production
340
2. **Use appropriate algorithms**: HS256 for symmetric keys, RS256/ES256 for asymmetric
341
3. **Validate claims**: Always verify `aud`, `iss`, and other relevant claims
342
4. **Handle expiration**: Use appropriate `exp` times and handle `ExpiredSignatureError`
343
5. **Clock skew**: Use `leeway` option to handle small time differences between systems
344
6. **Key management**: Rotate keys regularly and use `kid` header for key identification