JWT validation library for Python services.
- Validates
Usertokens - Validates
Auth0tokens - Exposes a clean library API for other services
- Shared and consistent JWT validation across services
- Built-in issuer, audience, signature, and claim checks
- Ready-to-run examples for both token types
- Unit and integration test coverage
- Strategy pattern for multi-token-type support —
UserAuthenticatorandAuth0Authenticatorshare a common interface; adding a new token type (e.g. API key) requires only a new strategy implementation. - Async JWKS fetching with TTL cache —
AsyncJWKSFetcheruses retry logic and cache expiry to minimize network calls while staying secure against key rotation. - Composable claim rules —
RequireRole,RequireAnyScope,RequireClaim, etc. are reusable rule objects that can be mixed and matched per endpoint; no hardcoded authorization logic. - Separation of cryptographic and business validation —
JWTVerifierhandles JOSE/signature verification;TokenProfile+ClaimValidatorhandle domain rules. Each layer is independently testable. - Library-first design — zero framework coupling; installable via
poetry addfrom any Python service with no transitive web dependencies. - Unit + integration test coverage — cryptographic verification, claim validation, JWKS fetching, and end-to-end token flows are all covered with pytest.
jwt-lib = { git = "https://github.com:vyavasthita/token-validator.git", branch = "main" }poetry add "git+https://github.com:vyavasthita/token-validator.git"Validating User Token
from jwt_lib.authenticator import UserAuthenticator
authenticator = UserAuthenticator(
issuer="https://login.example.com/",
jwks_host="https://login.example.com/",
audience="my-first-party-app",
)
claims = await authenticator.validate(token)
print(claims.subject)| Rule | Logic | Claim | Use case |
|---|---|---|---|
RequireRole |
AND | roles (list) |
Endpoint needs all listed roles |
RequireAnyRole |
OR | roles (list) |
Endpoint needs any one of the listed roles |
RequireScopes |
AND | scope (str) |
Endpoint needs all listed OAuth scopes |
RequireAnyScope |
OR | scope (str) |
Endpoint needs any one OAuth scope |
RequireClaim |
exact | any | Claim must exist (optionally with a specific value) |
RequireSubject |
exact | sub |
Token must belong to a specific subject |
RequireGrantType |
exact | gty |
Token must have a specific grant type |
RequireClaimIn |
in-set | any | Claim value must be one of an allowed set |
The library logs under the jwt_lib namespace (e.g. jwt_lib.authenticator.user_authenticator, jwt_lib.verifier.base_verifier). By default Python loggers inherit the root level, which is WARNING — so INFO-level messages like successful validations won't appear unless you explicitly configure the level:
import logging
logging.getLogger("jwt_lib").setLevel(logging.INFO) # or DEBUG for full detailKey log events:
| Level | Example |
|---|---|
INFO |
UserJWTVerifier succeeded issuer=auth-service, audience=auth-service. |
INFO |
UserProfile validation passed profile=UserProfile. |
WARNING |
UserAuthenticator validation failed for issuer=auth-service, error=… |
DEBUG |
Fetching JWKS from http://auth-service:2002/auth-service/token/.well-known/jwks.json |
cd token-validatorpoetry install --extras test--extras test installs local test-only dependencies while keeping published package dependencies lean.
Examples are available in examples/.
export AUTH_USER_ISSUER="https://login.example.com/"
export AUTH_USER_JWKS_HOST="https://login.example.com/"
export AUTH_USER_AUDIENCE="my-first-party-app"
export AUTH_TOKEN="<jwt here>"
poetry run python examples/user_token_validation_example.pyexport AUTH_0_ISSUER="https://tenant.auth0.com/"
export AUTH_0_JWKS_HOST="https://tenant.auth0.com/"
export AUTH_0_AUDIENCE="https://api.example.com"
export AUTH_0_TOKEN="<jwt here>"
poetry run python examples/auth0_token_validation_example.pypoetry run python examples/architecture_summary_example.pypoetry run pytestThis document shows how token-validator combines cryptographic verification and business claim validation.
flowchart TB
service[Client Service] --> authenticator[Authenticator]
subgraph Cryptographic Validation
authenticator --> verifier[JWTVerifier]
verifier --> jwks[AsyncJWKSFetcher]
verifier --> cache[(Signing Key Cache)]
verifier --> trusted[TrustedClaims]
end
subgraph Business Validation
authenticator --> profile[TokenProfile]
profile --> validator[ClaimValidator]
validator --> rules[ClaimRule Set]
end
trusted --> decision{Allow / Reject}
rules --> decision
sequenceDiagram
participant S as Service
participant A as Authenticator
participant V as JWTVerifier
participant F as AsyncJWKSFetcher
participant P as TokenProfile
participant C as ClaimValidator
S->>A: validate(token)
A->>V: validate(token)
V->>V: parse header + verify algorithm
V->>F: fetch JWKS (cache/TTL/retry)
F-->>V: jwks keys
V->>V: verify signature + iss/aud/exp/nbf/iat
V-->>A: TrustedClaims
A->>P: profile.validate(claims)
P->>C: execute rules
C-->>P: pass/fail
P-->>A: pass/fail
A-->>S: TrustedClaims or exception
Authenticator: single entry point for each token type.JWTVerifier: JOSE header checks, JWKS resolution, cryptographic verification.AsyncJWKSFetcher: HTTP fetch + retry + TTL caching for JWKS document.TokenProfile: token-type-specific business checks.ClaimValidator: executes reusableClaimRuleobjects.TrustedClaims: immutable container returned after successful verification.
| Area | Rules |
|---|---|
| Header | kid present, typ=JWT, alg=RS256 |
| Standard claims | iss, aud, exp, nbf, iat |
| Domain claims | tokenType=UserAuthToken, principalType=USER, connectionMethod in {SAML, UIDPWD} |
| Area | Rules |
|---|---|
| Header | allowed algorithm |
| Standard claims | iss, optional aud, exp |
| Domain claims | gty=client-credentials, optional appName |
Project Layout
token-validator/
src/jwt_lib/
tests/
examples/
MIT — Copyright © 2026 Dilip Kumar Sharma.