Skip to content

Commit 9fdf046

Browse files
miguelgrinbergjimmo
authored andcommitted
python-ecosys/pyjwt: Add pyjwt-compatible module.
1 parent 70e422d commit 9fdf046

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

python-ecosys/pyjwt/jwt.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import binascii
2+
import hashlib
3+
import hmac
4+
import json
5+
from time import time
6+
7+
def _to_b64url(data):
8+
return (
9+
binascii.b2a_base64(data)
10+
.rstrip(b"\n")
11+
.rstrip(b"=")
12+
.replace(b"+", b"-")
13+
.replace(b"/", b"_")
14+
)
15+
16+
17+
def _from_b64url(data):
18+
return binascii.a2b_base64(data.replace(b"-", b"+").replace(b"_", b"/") + b"===")
19+
20+
21+
class exceptions:
22+
class PyJWTError(Exception):
23+
pass
24+
25+
class InvalidTokenError(PyJWTError):
26+
pass
27+
28+
class InvalidAlgorithmError(PyJWTError):
29+
pass
30+
31+
class InvalidSignatureError(PyJWTError):
32+
pass
33+
34+
class ExpiredSignatureError(PyJWTError):
35+
pass
36+
37+
38+
def encode(payload, key, algorithm="HS256"):
39+
if algorithm != "HS256":
40+
raise exceptions.InvalidAlgorithmError
41+
42+
if isinstance(key, str):
43+
key = key.encode()
44+
header = _to_b64url(json.dumps({"typ": "JWT", "alg": algorithm}).encode())
45+
payload = _to_b64url(json.dumps(payload).encode())
46+
signature = _to_b64url(hmac.new(key, header + b"." + payload, hashlib.sha256).digest())
47+
return (header + b"." + payload + b"." + signature).decode()
48+
49+
50+
def decode(token, key, algorithms=["HS256"]):
51+
if "HS256" not in algorithms:
52+
raise exceptions.InvalidAlgorithmError
53+
54+
parts = token.encode().split(b".")
55+
if len(parts) != 3:
56+
raise exceptions.InvalidTokenError
57+
58+
try:
59+
header = json.loads(_from_b64url(parts[0]).decode())
60+
payload = json.loads(_from_b64url(parts[1]).decode())
61+
signature = _from_b64url(parts[2])
62+
except Exception:
63+
raise exceptions.InvalidTokenError
64+
65+
if header["alg"] not in algorithms or header["alg"] != "HS256":
66+
raise exceptions.InvalidAlgorithmError
67+
68+
if isinstance(key, str):
69+
key = key.encode()
70+
calculated_signature = hmac.new(key, parts[0] + b"." + parts[1], hashlib.sha256).digest()
71+
if signature != calculated_signature:
72+
raise exceptions.InvalidSignatureError
73+
74+
if "exp" in payload:
75+
if time() > payload["exp"]:
76+
raise exceptions.ExpiredSignatureError
77+
78+
return payload

python-ecosys/pyjwt/test_jwt.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import jwt
2+
from time import time
3+
4+
secret_key = "top-secret!"
5+
6+
token = jwt.encode({"user": "joe"}, secret_key, algorithm="HS256")
7+
print(token)
8+
decoded = jwt.decode(token, secret_key, algorithms=["HS256"])
9+
if decoded != {"user": "joe"}:
10+
raise Exception("Invalid decoded JWT")
11+
else:
12+
print("Encode/decode test: OK")
13+
14+
try:
15+
decoded = jwt.decode(token, "wrong-secret", algorithms=["HS256"])
16+
except jwt.exceptions.InvalidSignatureError:
17+
print("Invalid signature test: OK")
18+
else:
19+
raise Exception("Invalid JWT should have failed decoding")
20+
21+
token = jwt.encode({"user": "joe", "exp": time() - 1}, secret_key)
22+
print(token)
23+
try:
24+
decoded = jwt.decode(token, secret_key, algorithms=["HS256"])
25+
except jwt.exceptions.ExpiredSignatureError:
26+
print("Expired token test: OK")
27+
else:
28+
raise Exception("Expired JWT should have failed decoding")

0 commit comments

Comments
 (0)