jwt_generator
Generate and verify JSON Web Tokens (JWT) in pure Dart (Dart 3).
- Focused, dependency-light primitives
- RS256 (RSA + SHA-256) signing & verification
- HS256 (HMAC-SHA256) signing & verification
- Works with PEM RSA keys (via
RsaKeyParser) and JWK (viaRS256Verifier.fromJwk)
✨ Features
-
Build headers/claims via your DTOs (e.g.
FcmTokenDto/TokenDto) -
Sign JWTs
- RS256 using
RsaSignifier(PointyCastle) - HS256 using
HmacSignifier(package:crypto)
- RS256 using
-
Verify
- RS256 helper:
verifyJwtRs256(jwt, RSAPublicKey)(easy path) - RS256 generic:
RS256Verifier(incl.fromJwk) orRsaSignatureVerifierfor rawheader.payload - HS256 generic:
HmacSignatureVerifier(shared secret)
- RS256 helper:
-
Parse compact tokens to parts:
ParsedJwt.parse(token)→ header, payload, signature, andsigningInputbytes -
PEM parsing helpers:
RsaKeyParser.extractPrivateKey(...),extractPublicKey(...)
🚀 Install
# Dart
dart pub add jwt_generator
# Flutter
flutter pub add jwt_generator
Import:
import 'package:jwt_generator/jwt_generator.dart';
🔐 Key management (RSA)
Never commit real keys. For local testing:
# Generate a 2048-bit RSA private key (PKCS#1)
openssl genrsa -out private.pem 2048
# Derive the matching public key
openssl rsa -in private.pem -pubout -out public.pem
Load them with RsaKeyParser:
final parser = RsaKeyParser();
final RSAPrivateKey priv = parser.extractPrivateKey(pemPrivateKey);
final RSAPublicKey pub = parser.extractPublicKey(pemPublicKey);
Store secrets securely (env/Secret Manager). Do not ship PEMs in apps.
🧪 Quick start
RS256: sign + verify
import 'package:jwt_generator/jwt_generator.dart';
void main() {
// Parse keys
final parser = RsaKeyParser();
final priv = parser.extractPrivateKey(pemPrivateKey);
final pub = parser.extractPublicKey(pemPublicKey);
// Build a token (use your own DTO that implements buildHeader/buildClaims)
final signifier = RsaSignifier(privateKey: priv);
final builder = JwtBuilder(signifier: signifier);
final token = FcmTokenDto(
iss: 'you@example.com',
iat: DateTime.now(),
);
final jwt = builder.buildToken(token);
print('JWT: $jwt');
// Verify (helper)
final ok = verifyJwtRs256(jwt, pub);
print('RS256 signature valid? $ok');
// Or: verify via JWK
// final verifier = RS256Verifier.fromJwk(jwkMap);
// final ok = verifier.verify(jwt);
}
HS256: sign + verify
import 'package:jwt_generator/jwt_generator.dart';
void main() {
// Shared secret (bytes)
final secret = 'super-secret-change-me'.codeUnits;
// Sign
final hmacSign = HmacSignifier(secret: secret);
final builder = JwtBuilder(signifier: hmacSign);
final jwt = builder.buildToken(TokenDto({'sub': '123'}));
print('HS256 JWT: $jwt');
// Verify
final parsed = ParsedJwt.parse(jwt);
final verifier = HmacSignatureVerifier(secret: secret);
final valid = verifier.verify(parsed.signingInput, parsed.signatureBytes());
print('HS256 signature valid? $valid');
}
🧩 Parsing tokens
final parsed = ParsedJwt.parse(jwt);
print(parsed.header); // Map<String, Object?>
print(parsed.payload); // Map<String, Object?>
print(parsed.signatureB64); // Base64URL signature (no '=' padding)
final bytes = parsed.signingInput; // Uint8List of "header.payload"
📦 API surface (exports)
-
JwtBuilder– encodes & signs compact JWTs -
Signifierimplementations:RsaSignifier(RS256)HmacSignifier(HS256)
-
SignatureVerifierimplementations:RsaSignatureVerifier(RS256)HmacSignatureVerifier(HS256)
-
RS256Verifier(JWK/BigInt RSA verify) andverifyJwtRs256(...)helper -
RsaKeyParser– PEM →RSAPrivateKey/RSAPublicKey -
ParsedJwt– parse compact JWTs -
JwtException– package-wide error type -
tools.dart– Base64URL helpers, etc.
❗ Troubleshooting
- “Invalid or malformed JWT” – Ensure token has exactly 3 segments:
header.payload.signature. - “Bad signature” – Check key pair matches; confirm algorithm (
alg) isRS256for RSA orHS256for HMAC; ensure you didn’t modify whitespace or JSON formatting after signing. - PEM errors – Confirm PEM headers/footers are intact; avoid encrypted private keys for local tests.
- Clock skew – If you add
iat/expin your claims, account for small clock differences.