A Crystal library for JWT verification with RS256 and automatic JWKS fetching from OIDC providers.
- RS256 signature verification
- Automatic JWKS fetching and caching with OIDC discovery
- Standard claims validation (
exp,iat,nbf,iss,aud) - Thread-safe public key caching
- Automatic JWKS refresh with configurable TTL
Add this to your application's shard.yml:
dependencies:
jwt:
github: 84codes/jwt.crThen run:
shards installrequire "jwt"
# Create JWKS fetcher and start background refresh
fetcher = JWT::JWKSFetcher.new(
issuer_url: "https://auth.example.com",
default_cache_ttl: 1.hour
)
spawn { fetcher.refresh_loop }
# Configure and create verifier
config = JWT::VerifierConfig.new(
expected_issuer: "https://auth.example.com",
expected_audience: "my-api",
verify_audience: true
)
verifier = JWT::Verifier.new(config, fetcher.public_keys)
# Verify tokens
token = verifier.verify(jwt_string)
puts token.payload["sub"]The JWKS fetcher automatically:
- Fetches
{issuer_url}/.well-known/openid-configuration - Fetches public keys from the
jwks_uri - Refreshes keys based on
Cache-Controlheaders ordefault_cache_ttl
require "jwt"
# With verification
token = JWT::RS256Parser.decode(jwt_string, public_key_pem)
# Without verification (testing only)
token = JWT::RS256Parser.decode(jwt_string, "", verify: false)# VerifierConfig
config = JWT::VerifierConfig.new(
expected_issuer: "https://auth.example.com",
expected_audience: "my-api",
verify_audience: true,
time_tolerance: 200.milliseconds # Clock skew tolerance for iat validation
)
# JWKSFetcher
fetcher = JWT::JWKSFetcher.new(
issuer_url: "https://auth.example.com",
default_cache_ttl: 1.hour # Used if no Cache-Control header
)
# Stop the refresh loop gracefully
fetcher.stop
# Manually trigger a refresh
fetcher.trigger_refresh- Only RS256 algorithm accepted (prevents algorithm confusion attacks)
- Validates
exp,iat,nbftime claims - Optional
issandaudclaim validation - Supports multiple keys with
kid(Key ID) lookup - Thread-safe key caching
crystal specApache License 2.0