JWT Verify
Rust library for verifying JWTs signed by Amazon Cognito, and any OIDC-compatible IDP.
Inspired by awslabs/aws-jwt-verify.
Features
- Comprehensive validation of JWT tokens (ID tokens and Access tokens)
- Support for both AWS Cognito and generic OIDC providers
- Efficient JWK key management with automatic caching
- Multiple user pools/providers with automatic issuer matching
- Multiple client IDs per pool/provider
- Configurable clock skew and cache duration
- JWK prefetching (hydration) for cold start optimization
- Detailed error handling and reporting
- Thread-safe for use in async contexts
- Integration with popular Rust web frameworks (Axum)
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Quick Start
Verifying AWS Cognito Tokens
use ;
async
Verifying OIDC Tokens
use ;
async
Advanced Usage
Single Pool with Multiple Client IDs
A common use case is having one user pool with multiple client IDs (e.g., web app, mobile app):
use ;
use Duration;
async
Multiple User Pools
The verifier automatically selects the correct user pool based on the token's issuer claim:
use ;
async
JWK Prefetching (Hydration)
Prefetch JWKs to avoid cold start latency:
use ;
async
Multiple OIDC Providers
use ;
async
Examples
The library includes comprehensive examples demonstrating various use cases:
cognito_basic.rs: AWS Cognito JWT verification including:- Single user pool with single client ID
- Multiple user pools with different client IDs
- Single user pool with multiple client IDs (web/mobile apps)
- Negative test cases (wrong token types, expired tokens, etc.)
oidc_basic.rs: OIDC JWT verification including:- Single provider with single client ID
- Multiple providers with different client IDs
- Single provider with multiple client IDs
- Negative test cases
Running Examples
-
Set up configuration using a
.envfile:# Edit .env with your actual configuration -
Run the examples:
Example Configuration
The examples support various configurations through environment variables:
# Single user pool with multiple client IDs
AWS_REGION=us-east-1
COGNITO_USER_POOL_ID=us-east-1_example
COGNITO_CLIENT_ID=web-app-client-id
COGNITO_CLIENT_ID_2=mobile-app-client-id
# Your test tokens
COGNITO_ID_TOKEN=your-id-token
COGNITO_ACCESS_TOKEN=your-access-token
See examples/README.md for detailed configuration instructions and more examples.
Common Use Cases
ID Token vs Access Token
- ID Tokens: Used for authentication - contains user identity information (email, name, etc.)
- Access Tokens: Used for authorization - contains scopes and permissions
// Verify ID token for authentication
let id_claims = verifier.verify_id_token.await?;
println!;
// Verify access token for authorization
let access_claims = verifier.verify_access_token.await?;
if access_claims.has_scope
Error Handling
The library provides detailed error information for debugging:
match verifier.verify_id_token.await
Best Practices
- Reuse verifier instances: Create a single verifier instance and reuse it for all verifications (thread-safe)
- Set appropriate clock skew: Use 1-2 minutes to account for time differences between systems
- Configure cache duration: Match your IdP's key rotation policy (default: 12 hours)
- Prefetch JWKs: Use
hydrate()to warm up the cache and avoid cold start latency - Use correct token types: ID tokens for authentication, access tokens for authorization
- Validate scopes: Always check scopes in access tokens for authorization decisions
- Handle errors gracefully: Don't expose detailed error information to clients in production
- Multiple client IDs: Use a single pool/provider config with multiple client IDs for different apps (web, mobile)
License
This project is licensed under the MIT License.