44[ ![ appveyor-status-image]] [ appveyor ]
55[ ![ pypi-version-image]] [ pypi ]
66[ ![ coveralls-status-image]] [ coveralls ]
7+ [ ![ docs-status-image]] [ docs ]
78
8- A Python implementation of [ JSON Web Token draft 32 ] [ jwt-spec ] .
9+ A Python implementation of [ RFC 7519 ] [ jwt-spec ] .
910Original implementation was written by [ @progrium ] [ progrium ] .
1011
1112## Installing
@@ -14,114 +15,15 @@ Original implementation was written by [@progrium][progrium].
1415$ pip install PyJWT
1516```
1617
17- ** A Note on Dependencies** :
18-
19- RSA and ECDSA signatures depend on the recommended ` cryptography ` package (0.8+). If you plan on
20- using any of those algorithms, you'll need to install it as well.
21-
22- ```
23- $ pip install cryptography
24- ```
25-
26- If your system doesn't allow installing ` cryptography ` like on Google App Engine, you can install ` PyCrypto ` for RSA signatures and ` ecdsa ` for ECDSA signatures.
27-
2818## Usage
2919
3020``` python
3121>> > import jwt
3222>> > encoded = jwt.encode({' some' : ' payload' }, ' secret' , algorithm = ' HS256' )
3323' eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'
34- ```
35-
36- Additional headers may also be specified.
37-
38- ``` python
39- >> > jwt.encode({' some' : ' payload' }, ' secret' , algorithm = ' HS256' , headers = {' kid' : ' 230498151c214b788dd97f22b85410a5' })
40- ' eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIzMDQ5ODE1MWMyMTRiNzg4ZGQ5N2YyMmI4NTQxMGE1In0.eyJzb21lIjoicGF5bG9hZCJ9.DogbDGmMHgA_bU05TAB-R6geQ2nMU2BRM-LnYEtefwg'
41- ```
42-
43- Note the resulting JWT will not be encrypted, but verifiable with a secret key.
44-
45- ``` python
46- >> > jwt.decode(encoded, ' secret' , algorithms = [' HS256' ])
47- {u ' some' : u ' payload' }
48- ```
49-
50- If the secret is wrong, it will raise a ` jwt.DecodeError ` telling you as such.
51- You can still get the payload by setting the ` verify ` argument to ` False ` .
52-
53- ``` python
54- >> > jwt.decode(encoded, verify = False )
55- {u ' some' : u ' payload' }
56- ```
57-
58- ## Validation
59- Exceptions can be raised during ` decode() ` for other errors besides an
60- invalid signature (e.g. for invalid issuer or audience (see below). All
61- exceptions that signify that the token is invalid extend from the base
62- ` InvalidTokenError ` exception class, so applications can use this approach to
63- catch any issues relating to invalid tokens:
64-
65- ``` python
66- try :
67- payload = jwt.decode(encoded)
68- except jwt.InvalidTokenError:
69- pass # do something sensible here, e.g. return HTTP 403 status code
70- ```
71-
72- ### Skipping Claim Verification
73- You may also override claim verification via the ` options ` dictionary. The
74- default options are:
75-
76- ``` python
77- options = {
78- ' verify_signature' : True ,
79- ' verify_exp' : True ,
80- ' verify_nbf' : True ,
81- ' verify_iat' : True ,
82- ' verify_aud' : True
83- ' require_exp' : False ,
84- ' require_iat' : False ,
85- ' require_nbf' : False
86- }
87- ```
88-
89- You can skip validation of individual claims by passing an ` options ` dictionary
90- with the "verify_ <claim_name>" key set to ` False ` when you call ` jwt.decode() ` .
91- For example, if you want to verify the signature of a JWT that has already
92- expired, you could do so by setting ` verify_exp ` to ` False ` .
93-
94- ``` python
95- >> > options = {
96- >> > ' verify_exp' : False ,
97- >> > }
98-
99- >> > encoded = ' ...' # JWT with an expired exp claim
100- >> > jwt.decode(encoded, ' secret' , options = options)
101- {u ' some' : u ' payload' }
102- ```
103-
104- ** NOTE** : * Changing the default behavior is done at your own risk, and almost
105- certainly will make your application less secure. Doing so should only be done
106- with a very clear understanding of what you are doing.*
107-
108- ### Requiring Optional Claims
109- In addition to skipping certain validations, you may also specify that certain
110- optional claims are required by setting the appropriate ` require_<claim_name> `
111- option to True. If the claim is not present, PyJWT will raise a
112- ` jwt.exceptions.MissingRequiredClaimError ` .
113-
114- For instance, the following code would require that the token has a 'exp'
115- claim and raise an error if it is not present:
11624
117- ``` python
118- >> > options = {
119- >> > ' require_exp' : True
120- >> > }
121-
122- >> > encoded = ' ...' # JWT without an exp claim
123- >> > jwt.decode(encoded, ' secret' , options = options)
124- jwt.exceptions.MissingRequiredClaimError: Token is missing the " exp" claim
25+ >> > jwt.decode(encoded, ' secret' . algorithms= [' HS256' ])
26+ {' some' : ' payload' }
12527```
12628
12729## Tests
@@ -132,244 +34,6 @@ You can run tests from the project root after cloning with:
13234$ python setup.py test
13335```
13436
135- ## Algorithms
136-
137- The JWT spec supports several algorithms for cryptographic signing. This library
138- currently supports:
139-
140- * HS256 - HMAC using SHA-256 hash algorithm (default)
141- * HS384 - HMAC using SHA-384 hash algorithm
142- * HS512 - HMAC using SHA-512 hash algorithm
143- * ES256 - ECDSA signature algorithm using SHA-256 hash algorithm
144- * ES384 - ECDSA signature algorithm using SHA-384 hash algorithm
145- * ES512 - ECDSA signature algorithm using SHA-512 hash algorithm
146- * RS256 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-256 hash algorithm
147- * RS384 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-384 hash algorithm
148- * RS512 - RSASSA-PKCS1-v1_5 signature algorithm using SHA-512 hash algorithm
149- * PS256 - RSASSA-PSS signature using SHA-256 and MGF1 padding with SHA-256
150- * PS384 - RSASSA-PSS signature using SHA-384 and MGF1 padding with SHA-384
151- * PS512 - RSASSA-PSS signature using SHA-512 and MGF1 padding with SHA-512
152-
153- ### Encoding
154- You can specify which algorithm you would like to use to sign the JWT
155- by using the ` algorithm ` parameter:
156-
157- ``` python
158- >> > encoded = jwt.encode({' some' : ' payload' }, ' secret' , algorithm = ' HS512' )
159- ' eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.WTzLzFO079PduJiFIyzrOah54YaM8qoxH9fLMQoQhKtw3_fMGjImIOokijDkXVbyfBqhMo2GCNu4w9v7UXvnpA'
160- ```
161-
162- ### Decoding
163- When decoding, you can specify which algorithms you would like to permit
164- when validating the JWT by using the ` algorithms ` parameter which takes a list
165- of allowed algorithms:
166-
167- ``` python
168- >> > jwt.decode(encoded, ' secret' , algorithms = [' HS512' , ' HS256' ])
169- {u ' some' : u ' payload' }
170- ```
171-
172- In the above case, if the JWT has any value for its alg header other than
173- HS512 or HS256, the claim will be rejected with an ` InvalidAlgorithmError ` .
174-
175- ### Asymmetric (Public-key) Algorithms
176- Usage of RSA (RS\* ) and EC (EC\* ) algorithms require a basic understanding
177- of how public-key cryptography is used with regards to digital signatures.
178- If you are unfamiliar, you may want to read
179- [ this article] ( http://en.wikipedia.org/wiki/Public-key_cryptography ) .
180-
181- When using the RSASSA-PKCS1-v1_5 algorithms, the ` key ` argument in both
182- ` jwt.encode() ` and ` jwt.decode() ` (` "secret" ` in the examples) is expected to
183- be either an RSA public or private key in PEM or SSH format. The type of key
184- (private or public) depends on whether you are signing or verifying.
185-
186- When using the ECDSA algorithms, the ` key ` argument is expected to
187- be an Elliptic Curve public or private key in PEM format. The type of key
188- (private or public) depends on whether you are signing or verifying.
189-
190-
191- ## Support of registered claim names
192-
193- JSON Web Token defines some registered claim names and defines how they should
194- be used. PyJWT supports these registered claim names:
195-
196- - "exp" (Expiration Time) Claim
197- - "nbf" (Not Before Time) Claim
198- - "iss" (Issuer) Claim
199- - "aud" (Audience) Claim
200- - "iat" (Issued At) Claim
201-
202- ### Expiration Time Claim
203-
204- From [ the JWT spec] [ jwt-spec-reg-claims ] :
205-
206- > The "exp" (expiration time) claim identifies the expiration time on
207- > or after which the JWT MUST NOT be accepted for processing. The
208- > processing of the "exp" claim requires that the current date/time
209- > MUST be before the expiration date/time listed in the "exp" claim.
210- > Implementers MAY provide for some small leeway, usually no more than
211- > a few minutes, to account for clock skew. Its value MUST be a number
212- > containing a NumericDate value. Use of this claim is OPTIONAL.
213-
214- You can pass the expiration time as a UTC UNIX timestamp (an int) or as a
215- datetime, which will be converted into an int. For example:
216-
217- ``` python
218- jwt.encode({' exp' : 1371720939 }, ' secret' )
219-
220- jwt.encode({' exp' : datetime.utcnow()}, ' secret' )
221- ```
222-
223- Expiration time is automatically verified in ` jwt.decode() ` and raises
224- ` jwt.ExpiredSignatureError ` if the expiration time is in the past:
225-
226- ``` python
227- import jwt
228-
229- try :
230- jwt.decode(' JWT_STRING' , ' secret' )
231- except jwt.ExpiredSignatureError:
232- # Signature has expired
233- ```
234-
235- Expiration time will be compared to the current UTC time (as given by
236- ` timegm(datetime.utcnow().utctimetuple()) ` ), so be sure to use a UTC timestamp
237- or datetime in encoding.
238-
239- You can turn off expiration time verification with the ` verify_exp ` parameter in the options argument.
240-
241- PyJWT also supports the leeway part of the expiration time definition, which
242- means you can validate a expiration time which is in the past but not very far.
243- For example, if you have a JWT payload with a expiration time set to 30 seconds
244- after creation but you know that sometimes you will process it after 30 seconds,
245- you can set a leeway of 10 seconds in order to have some margin:
246-
247- ``` python
248- import datetime
249- import time
250- import jwt
251-
252- jwt_payload = jwt.encode({
253- ' exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds = 30 )
254- }, ' secret' )
255-
256- time.sleep(32 )
257-
258- # JWT payload is now expired
259- # But with some leeway, it will still validate
260- jwt.decode(jwt_payload, ' secret' , leeway = 10 )
261- ```
262-
263- Instead of specifying the leeway as a number of seconds, a ` datetime.timedelta `
264- instance can be used. The last line in the example above is equivalent to:
265-
266- ``` python
267- jwt.decode(jwt_payload, ' secret' , leeway = datetime.timedelta(seconds = 10 ))
268- ```
269-
270-
271- ### Not Before Time Claim
272-
273- > The "nbf" (not before) claim identifies the time before which the JWT
274- > MUST NOT be accepted for processing. The processing of the "nbf"
275- > claim requires that the current date/time MUST be after or equal to
276- > the not-before date/time listed in the "nbf" claim. Implementers MAY
277- > provide for some small leeway, usually no more than a few minutes, to
278- > account for clock skew. Its value MUST be a number containing a
279- > NumericDate value. Use of this claim is OPTIONAL.
280-
281- The ` nbf ` claim works similarly to the ` exp ` claim above.
282-
283- ``` python
284- jwt.encode({' nbf' : 1371720939 }, ' secret' )
285-
286- jwt.encode({' nbf' : datetime.utcnow()}, ' secret' )
287- ```
288-
289- ### Issuer Claim
290-
291- > The "iss" (issuer) claim identifies the principal that issued the
292- > JWT. The processing of this claim is generally application specific.
293- > The "iss" value is a case-sensitive string containing a StringOrURI
294- > value. Use of this claim is OPTIONAL.
295-
296- ``` python
297- import jwt
298-
299-
300- payload = {
301- ' some' : ' payload' ,
302- ' iss' : ' urn:foo'
303- }
304-
305- token = jwt.encode(payload, ' secret' )
306- decoded = jwt.decode(token, ' secret' , issuer = ' urn:foo' )
307- ```
308-
309- If the issuer claim is incorrect, ` jwt.InvalidIssuerError ` will be raised.
310-
311-
312- ### Audience Claim
313-
314- > The "aud" (audience) claim identifies the recipients that the JWT is
315- > intended for. Each principal intended to process the JWT MUST
316- > identify itself with a value in the audience claim. If the principal
317- > processing the claim does not identify itself with a value in the
318- > "aud" claim when this claim is present, then the JWT MUST be
319- > rejected. In the general case, the "aud" value is an array of case-
320- > sensitive strings, each containing a StringOrURI value. In the
321- > special case when the JWT has one audience, the "aud" value MAY be a
322- > single case-sensitive string containing a StringOrURI value. The
323- > interpretation of audience values is generally application specific.
324- > Use of this claim is OPTIONAL.
325-
326- ``` python
327- import jwt
328-
329-
330- payload = {
331- ' some' : ' payload' ,
332- ' aud' : ' urn:foo'
333- }
334-
335- token = jwt.encode(payload, ' secret' )
336- decoded = jwt.decode(token, ' secret' , audience = ' urn:foo' )
337- ```
338-
339- If the audience claim is incorrect, ` jwt.InvalidAudienceError ` will be raised.
340-
341- ### Issued At Claim
342-
343- > The iat (issued at) claim identifies the time at which the JWT was issued.
344- > This claim can be used to determine the age of the JWT. Its value MUST be a
345- > number containing a NumericDate value. Use of this claim is OPTIONAL.
346-
347- If the ` iat ` claim is in the future, an ` jwt.InvalidIssuedAtError ` exception
348- will be raised.
349-
350- ``` python
351- jwt.encode({' iat' : 1371720939 }, ' secret' )
352-
353- jwt.encode({' iat' : datetime.utcnow()}, ' secret' )
354- ```
355-
356- ## Frequently Asked Questions
357-
358- ** How can I extract a public / private key from a x509 certificate?**
359-
360- The ` load_pem_x509_certificate() ` function from ` cryptography ` can be used to
361- extract the public or private keys from a x509 certificate in PEM format.
362-
363- ``` python
364- from cryptography.x509 import load_pem_x509_certificate
365- from cryptography.hazmat.backends import default_backend
366-
367- cert_str = " -----BEGIN CERTIFICATE-----MIIDETCCAfm..."
368- cert_obj = load_pem_x509_certificate(cert_str, default_backend())
369- public_key = cert_obj.public_key()
370- private_key = cert_obj.private_key()
371- ```
372-
37337[ travis-status-image ] : https://secure.travis-ci.org/jpadilla/pyjwt.svg?branch=master
37438[ travis ] : http://travis-ci.org/jpadilla/pyjwt?branch=master
37539[ appveyor-status-image ] : https://ci.appveyor.com/api/projects/status/h8nt70aqtwhht39t?svg=true
@@ -378,6 +42,7 @@ private_key = cert_obj.private_key()
37842[ pypi ] : https://pypi.python.org/pypi/pyjwt
37943[ coveralls-status-image ] : https://coveralls.io/repos/jpadilla/pyjwt/badge.svg?branch=master
38044[ coveralls ] : https://coveralls.io/r/jpadilla/pyjwt?branch=master
381- [ jwt-spec ] : https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32
382- [ jwt-spec-reg-claims ] : http://self-issued.info/docs/draft-jones-json-web-token-01.html#ReservedClaimName
45+ [ docs-status-image ] : https://readthedocs.org/projects/pyjwt/badge/?version=latest
46+ [ docs ] : http://pyjwt.readthedocs.org
47+ [ jwt-spec ] : https://tools.ietf.org/html/rfc7519
38348[ progrium ] : https://github.com/progrium
0 commit comments