JWT Token#
A wrapper around PyJWT that simplifies encoding, decoding, and validation of JSON Web Tokens.
Quick Start#
from core_auth import JwtToken
client = JwtToken(private_key="S3cr3t")
# Encode
token = client.encode(subject="user-123")
# Decode
payload = client.decode(token)
print(payload["sub"]) # "user-123"
print(payload["exp"]) # expiry timestamp
print(payload["iat"]) # issued-at timestamp
Custom Claims & Expiry#
Any additional JWT claims can be passed via claims. The token lifetime is
controlled by expire (seconds, default 3600).
from core_auth import JwtToken
client = JwtToken(private_key="S3cr3t", expire=7200)
token = client.encode(
subject="user-123",
claims={
"iss": "my-auth-service",
"aud": "my-api",
"role": "admin",
},
)
payload = client.decode(token, audience="my-api", issuer="my-auth-service")
print(payload["role"]) # "admin"
Decode Options#
Audience and issuer validation
from core_auth import JwtToken, JwtException
client = JwtToken(private_key="S3cr3t")
token = client.encode(subject="user-123", claims={"iss": "auth", "aud": "api"})
# Validates that iss == "auth" and aud == "api"
payload = client.decode(token, issuer="auth", audience="api")
print(payload)
# Raises JwtException if either claim does not match
try:
client.decode(token, issuer="wrong")
except JwtException as exc:
print(exc) # "Invalid token."
Expiry leeway
Allow a small clock-skew grace period when validating exp:
from datetime import timedelta
from core_auth import JwtToken
client = JwtToken(private_key="S3cr3t")
token = client.encode(subject="user-123")
payload = client.decode(token, leeway=timedelta(seconds=30))
Skip signature verification
Useful for inspecting a token’s claims without validating the signature (e.g. in tests or debugging):
from core_auth import JwtToken
client = JwtToken(private_key="S3cr3t")
token = client.encode(subject="user-123")
payload = client.decode(token, options={"verify_signature": False})
Full decode — returns header, payload, and raw signature together:
from core_auth import JwtToken
client = JwtToken(private_key="S3cr3t")
token = client.encode(subject="user-123")
result = client.decode(token, full_decode=True)
print(result["header"]) # {'alg': 'HS256', 'typ': 'JWT'}
print(result["payload"]) # {'exp': ..., 'iat': ..., 'sub': 'user-123'}
print(result["signature"]) # b'...'
Custom Headers#
Additional JOSE header fields (e.g. kid for key ID rotation) can be injected
via headers:
from core_auth import JwtToken
client = JwtToken(private_key="S3cr3t")
token = client.encode(subject="user-123", headers={"kid": "key-v2"})
result = client.decode(token, full_decode=True)
print(result["header"]["kid"]) # "key-v2"
Asymmetric Keys (RSA / ECDSA / EdDSA)#
For asymmetric algorithms pass both private_key (for signing) and
public_key (for verification). Keys can be PEM strings, PEM bytes, or
cryptography key objects.
RSA — RS256
from core_auth import JwtToken, ALGORITHM
private_pem = open("tests/resources/private.pem").read()
public_pem = open("tests/resources/public.pem").read()
client = JwtToken(private_key=private_pem, public_key=public_pem)
token = client.encode(subject="user-123", algorithm=ALGORITHM.RS256)
payload = client.decode(token, algorithms=[ALGORITHM.RS256])
print(payload["sub"]) # "user-123"
ECDSA — ES256
from cryptography.hazmat.primitives.asymmetric import ec
from core_auth import JwtToken, ALGORITHM
private_key = ec.generate_private_key(ec.SECP256R1())
client = JwtToken(private_key=private_key, public_key=private_key.public_key())
token = client.encode(subject="user-123", algorithm=ALGORITHM.ES256)
payload = client.decode(token, algorithms=[ALGORITHM.ES256])
EdDSA — Ed25519 / Ed448
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from core_auth import JwtToken, ALGORITHM
private_key = Ed25519PrivateKey.generate()
client = JwtToken(private_key=private_key, public_key=private_key.public_key())
token = client.encode(subject="user-123", algorithm=ALGORITHM.EdDSA)
payload = client.decode(token, algorithms=[ALGORITHM.EdDSA])
Using cryptography key objects directly:
from cryptography.hazmat.primitives.asymmetric import rsa
from core_auth import JwtToken, ALGORITHM
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
client = JwtToken(private_key=private_key, public_key=private_key.public_key())
token = client.encode(subject="user-123", algorithm=ALGORITHM.RS256)
payload = client.decode(token, algorithms=[ALGORITHM.RS256])
Error Handling#
All errors raised by JwtToken are instances of JwtException, which is
itself a subclass of PyJWTError:
from core_auth import JwtToken, JwtException
client = JwtToken(private_key="S3cr3t")
try:
payload = client.decode("an.invalid.token")
except JwtException as exc:
print(exc) # "Invalid token."
# Expired token
expired_client = JwtToken(private_key="S3cr3t", expire=-1)
token = expired_client.encode(subject="user-123")
try:
expired_client.decode(token)
except JwtException as exc:
print(exc) # "Signature expired."
API Reference#
JWT token wrapper module for authentication operations.
- class core_auth.auth.jwt_token.jwt_auth.JwtToken(private_key: RSAPrivateKey | EllipticCurvePrivateKey | Ed25519PrivateKey | Ed448PrivateKey | PyJWK | bytes | str, public_key: RSAPublicKey | EllipticCurvePublicKey | Ed25519PublicKey | Ed448PublicKey | PyJWK | str | bytes | None = None, expire: int = 3600)[source]#
Bases:
objectWrapper around JWT tokens
- __init__(private_key: RSAPrivateKey | EllipticCurvePrivateKey | Ed25519PrivateKey | Ed448PrivateKey | PyJWK | bytes | str, public_key: RSAPublicKey | EllipticCurvePublicKey | Ed25519PublicKey | Ed448PublicKey | PyJWK | str | bytes | None = None, expire: int = 3600) None[source]#
- Parameters:
private_key – Secret key to create, encode and decode the tokens.
expire – Seconds until the token expires.
- static from_auth_header(auth_header: str) str[source]#
It retrieves the token from the authentication headers
- encode(subject: Any = None, algorithm: ALGORITHM | str = ALGORITHM.HS256, claims: Dict[str, Any] | None = None, headers: Dict | None = None, json_encoder: type[JSONEncoder] | None = None) str[source]#
Encode the payload as Json Web Token. More Info: https://pyjwt.readthedocs.io/en/stable/api.html#jwt.encode
- Parameters:
subject – Information will be place into the sub claim.
algorithm – Algorithm to use like: HS256.
claims – Other claims to add in the payload. For more information about standardized claims see: https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-claims https://www.iana.org/assignments/jwt/jwt.xhtml#claims
headers – Additional JWT header fields.
json_encoder – Custom JSON encoder for payload and headers.
- Returns:
The Json Web Token.
- decode(token: str, algorithms: List[ALGORITHM | str] | None = None, options: Dict | None = None, audience: List[str] | str | None = None, issuer: str | None = None, leeway: timedelta | float = 0, full_decode: bool = False) Dict[source]#
It decodes and verifies the JWT token signature and return the token claims. More Info: https://pyjwt.readthedocs.io/en/stable/api.html#jwt.decode
- Parameters:
token – Token to decode.
algorithms – Algorithms to use like: HS256 or RS256.
options – Extended decoding and validation options. - verify_signature=True verify the JWT cryptographic signature. - require=[] claims that must be present. - verify_aud=verify_signature check that aud claim matches audience - verify_iss=verify_signature check that iss claim matches issuer - verify_exp=verify_signature check that exp claim is in the future - verify_iat=verify_signature check that iat claim is an integer - verify_nbf=verify_signature check that nbf claim is in the past - strict_aud=False check aud is a single value matching audience exactly
audience – The value for verify_aud check.
issuer – The value for verify_iss check.
leeway – A time margin in seconds for the expiration check
full_decode – If True, full_decode will be performed.
- Returns:
The JWT claims or full payload.
Example:
# If full_decode. { 'payload': { 'exp': ..., 'iat': ..., 'sub': '...', 'iss': '...' }, 'header': { 'alg': 'HS256', 'typ': 'JWT' }, 'signature': b'...' } # Else. { 'exp': ..., 'iat': ..., 'sub': '...' }
Algorithms#
JWT algorithm enumeration for cryptographic signing operations.
- class core_auth.auth.jwt_token.algorithm.ALGORITHM(*values)[source]#
Bases:
StrEnumSupported algorithms for cryptographic signing. More info: https://pyjwt.readthedocs.io/en/stable/algorithms.html
- HS256 = 'HS256'#
- HS384 = 'HS384'#
- HS512 = 'HS512'#
- ES256 = 'ES256'#
- ES256K = 'ES256K'#
- ES384 = 'ES384'#
- ES512 = 'ES512'#
- RS256 = 'RS256'#
- RS384 = 'RS384'#
- RS512 = 'RS512'#
- PS256 = 'PS256'#
- PS384 = 'PS384'#
- PS512 = 'PS512'#
- EdDSA = 'EdDSA'#
- static _generate_next_value_(name, start, count, last_values)#
Return the lower-cased version of the member name.