A simple and secure API for generating QR codes from signed JWTs and verifying JWTs extracted from QR codes. Perfect for digital certificates, tickets, and secure data verification.
- 🔐 JWT Signing: Sign JSON data with HMAC-SHA256
- 📱 QR Code Scripts: Local scripts for QR code generation and verification
- ✅ JWT Verification: Verify and decode JWTs from QR codes
- 🛡️ Security: Built-in expiration, issuer validation, and unique identifiers
- ⚡ Fast: Built with Bun and Hono for optimal performance
- Bun installed on your system
# Clone the repository
git clone <repository-url>
cd cert-tools
# Install dependencies
bun install
# Set up environment
cp .env.example .env
# Edit .env and set your JWT_SECRETCreate a .env file with:
JWT_SECRET=your-secure-secret-key-here# Development mode (with hot reload)
bun run dev
# The server will start on http://localhost:3000POST /generate-jwt
Accepts JSON data, signs it as a JWT, and returns the signed token.
curl -X POST http://localhost:3000/generate-jwt \
-H "Content-Type: application/json" \
-d '{
"certificateId": "CERT-12345",
"recipientName": "John Doe",
"courseName": "Web Development Certification",
"issuerName": "Tech Academy",
"completionDate": "2024-01-15"
}'{
"success": true,
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"payload": {
"certificateId": "CERT-12345",
"recipientName": "John Doe",
"courseName": "Web Development Certification",
"issuerName": "Tech Academy",
"completionDate": "2024-01-15",
"iat": 1705401600,
"exp": 1705488000,
"iss": "cert-tools",
"jti": "550e8400-e29b-41d4-a716-446655440000"
}
}POST /verify-jwt
Verifies a JWT extracted from a QR code and returns the decoded data.
curl -X POST http://localhost:3000/verify-jwt \
-H "Content-Type: application/json" \
-d '{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'{
"success": true,
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"payload": {
"certificateId": "CERT-12345",
"recipientName": "John Doe",
"courseName": "Web Development Certification",
"iat": 1705401600,
"exp": 1705488000,
"iss": "cert-tools"
},
"verified": true
}GET /health
{
"status": "healthy",
"timestamp": "2024-01-15T10:30:00.000Z"
}GET /jwt-info
{
"algorithm": "HS256",
"issuer": "cert-tools",
"note": "JWTs are signed with HMAC-SHA256 using a secret key"
}This project includes local scripts for QR code operations that work with the API.
# Generate QR code with sample data
bun run generate-qr
# Generate QR code with custom data
bun run generate-qr '{"certificateId":"CERT-123","recipientName":"John Doe"}'
# Save QR code to file
bun run generate-qr '{"certificateId":"CERT-123"}' qrcode.png# Verify JWT from command line
bun run verify-qr "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Verify JWT from file
bun run verify-qr --file jwt.txt// Generate JWT
async function generateJWT(certificateData: any) {
const response = await fetch('/generate-jwt', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(certificateData)
});
const result = await response.json();
return result.jwt;
}
// Verify JWT
async function verifyCertificate(jwt: string) {
const response = await fetch('/verify-jwt', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jwt })
});
const result = await response.json();
if (result.verified) {
console.log('Certificate is valid:', result.payload);
} else {
console.log('Certificate verification failed');
}
return result;
}import requests
import json
# Generate JWT
def generate_jwt(data):
response = requests.post(
'http://localhost:3000/generate-jwt',
headers={'Content-Type': 'application/json'},
json=data
)
return response.json()
# Verify JWT
def verify_jwt(jwt_token):
response = requests.post(
'http://localhost:3000/verify-jwt',
headers={'Content-Type': 'application/json'},
json={'jwt': jwt_token}
)
return response.json()
# Example usage
certificate_data = {
'certificateId': 'CERT-12345',
'recipientName': 'John Doe',
'courseName': 'Python Programming'
}
result = generate_jwt(certificate_data)
print(f"JWT generated: {result['success']}")- Create Certificate Data: Prepare your certificate/ticket data as JSON
- Generate QR Code: Use
bun run generate-qrwith your data - Display/Save QR Code: The script will generate and save the QR code
- Scan QR Code: Use any QR scanner to extract the JWT
- Verify JWT: Use
bun run verify-qrwith the extracted JWT
- Create Certificate Data: Prepare your certificate/ticket data as JSON
- Generate JWT: Send data to
/generate-jwtendpoint - Create QR Code: Use any QR code library to encode the JWT
- Scan QR Code: Use any QR scanner to extract the JWT
- Verify JWT: Send extracted JWT to
/verify-jwtfor validation
- HMAC-SHA256: Cryptographically secure signing algorithm
- Expiration: JWTs expire after 24 hours by default
- Issuer Validation: All JWTs must be issued by 'cert-tools'
- Unique IDs: Each JWT has a unique identifier (jti claim)
- Timestamp Validation: Issued-at time prevents replay attacks
All endpoints return consistent error responses:
{
"error": "Error description",
"message": "Detailed error message"
}Common HTTP status codes:
200: Success400: Bad Request (invalid input)500: Internal Server Error
cert-tools/
├── src/
│ └── index.ts # Main API server
├── lib/
│ ├── jwt.ts # JWT signing and verification
│ └── qrcode.ts # QR code utilities (legacy)
├── scripts/
│ ├── generate-qr.ts # Local QR code generation script
│ └── verify-qr.ts # Local QR code verification script
├── .env # Environment variables
├── package.json # Dependencies
└── README.md # This file
- hono: Fast web framework
- qrcode: QR code generation (for local scripts)
- @types/qrcode: TypeScript definitions
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
MIT License - see LICENSE file for details.
For issues and questions:
- Create an issue on GitHub
- Check the API documentation above
- Review the example code
Built with ❤️ using Bun and Hono