fix: improve jwt errors

This commit is contained in:
Taimoor Zaeem
2025-03-13 00:20:54 +01:00
committed by Steve Chavez
parent 4819520e3a
commit 36b6a2c86b
7 changed files with 118 additions and 44 deletions
+38 -9
View File
@@ -92,7 +92,7 @@ def test_jwt_errors(defaultenv):
headers = jwtauthheader({}, "other secret")
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert response.json()["message"] == "JWSError JWSInvalidSignature"
assert response.json()["message"] == "No suitable key or wrong key type"
headers = jwtauthheader({"role": "not_existing"}, SECRET)
response = postgrest.session.get("/", headers=headers)
@@ -110,27 +110,30 @@ def test_jwt_errors(defaultenv):
headers = jwtauthheader({"nbf": relativeSeconds(31)}, SECRET)
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert response.json()["message"] == "JWTNotYetValid"
assert response.json()["message"] == "JWT not yet valid"
# 31 seconds, because we allow clock skew of 30 seconds
headers = jwtauthheader({"iat": relativeSeconds(31)}, SECRET)
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert response.json()["message"] == "JWTIssuedAtFuture"
assert response.json()["message"] == "JWT issued at future"
headers = jwtauthheader({"aud": "not set"}, SECRET)
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert response.json()["message"] == "JWTNotInAudience"
assert response.json()["message"] == "JWT not in audience"
# partial token, no signature
headers = authheader("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.bm90IGFuIG9iamVjdA")
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert (
response.json()["message"]
== "JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 2)"
)
assert response.json()["message"] == "Expected 3 parts in JWT; got 2"
# complete token but random characters
headers = authheader("quifquirndsjagnrgniur.fonvoienqhhdj.iuqvnvhojah")
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert response.json()["message"] == "JWT cryptographic operation failed"
# token with algorithm "none"
headers = authheader(
@@ -138,7 +141,33 @@ def test_jwt_errors(defaultenv):
)
response = postgrest.session.get("/", headers=headers)
assert response.status_code == 401
assert response.json()["message"] == "JWSError JWSNoSignatures"
assert response.json()["message"] == "Wrong or unsupported encoding algorithm"
env = {
**defaultenv,
"PGRST_SERVER_TIMING_ENABLED": "true",
"PGRST_JWT_CACHE_MAX_LIFETIME": "86400",
"PGRST_JWT_SECRET": SECRET,
}
# for code coverage with cache enabled and server-timing enabled
with run(env=env) as postgrest:
response = postgrest.session.get("/authors_only")
assert response.status_code == 401
assert response.json()["message"] == "permission denied for table authors_only"
env = {
**defaultenv,
"PGRST_SERVER_TIMING_ENABLED": "false",
"PGRST_JWT_CACHE_MAX_LIFETIME": "86400",
"PGRST_JWT_SECRET": SECRET,
}
# for code coverage with cache enabled and server-timing disabled
with run(env=env) as postgrest:
response = postgrest.session.get("/authors_only")
assert response.status_code == 401
assert response.json()["message"] == "permission denied for table authors_only"
def test_fail_with_invalid_password(defaultenv):
+14 -3
View File
@@ -85,10 +85,21 @@ spec = describe "authorization" $ do
request methodGet "/authors_only" [auth] ""
`shouldRespondWith` 200
it "fails when auth header is sent empty" $ do
let auth = authHeaderJWT ""
request methodGet "/authors_only" [auth] ""
`shouldRespondWith` [json| {"message":"Empty JWT is sent in Authorization header","code":"PGRST301","hint":null,"details":null} |]
{ matchStatus = 401
, matchHeaders = [
"WWW-Authenticate" <:>
"Bearer error=\"invalid_token\", error_description=\"Empty JWT is sent in Authorization header\""
]
}
it "fails with an expired token" $ do
let auth = authHeaderJWT "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NDY2NzgxNDksInJvbGUiOiJwb3N0Z3Jlc3RfdGVzdF9hdXRob3IiLCJpZCI6Impkb2UifQ.f8__E6VQwYcDqwHmr9PG03uaZn8Zh1b0vbJ9DYS0AdM"
request methodGet "/authors_only" [auth] ""
`shouldRespondWith` [json| {"message":"JWT expired","code":"PGRST301","hint":null,"details":null} |]
`shouldRespondWith` [json| {"message":"JWT expired","code":"PGRST303","hint":null,"details":null} |]
{ matchStatus = 401
, matchHeaders = [
"WWW-Authenticate" <:>
@@ -99,11 +110,11 @@ spec = describe "authorization" $ do
it "hides tables from users with invalid JWT" $ do
let auth = authHeaderJWT "ey9zdGdyZXN0X3Rlc3RfYXV0aG9yIiwiaWQiOiJqZG9lIn0.y4vZuu1dDdwAl0-S00MCRWRYMlJ5YAMSir6Es6WtWx0"
request methodGet "/authors_only" [auth] ""
`shouldRespondWith` [json| {"message":"JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 2)","code":"PGRST301","hint":null,"details":null} |]
`shouldRespondWith` [json| {"message":"Expected 3 parts in JWT; got 2","code":"PGRST301","hint":null,"details":null} |]
{ matchStatus = 401
, matchHeaders = [
"WWW-Authenticate" <:>
"Bearer error=\"invalid_token\", error_description=\"JWSError (CompactDecodeError Invalid number of parts: Expected 3 parts; got 2)\""
"Bearer error=\"invalid_token\", error_description=\"Expected 3 parts in JWT; got 2\""
]
}