secure_qr_generator 1.1.0 copy "secure_qr_generator: ^1.1.0" to clipboard
secure_qr_generator: ^1.1.0 copied to clipboard

A Flutter package for generating secure, auto-regenerating QR codes with encryption, digital signatures, and automatic expiration management.

Secure QR Generator #

A Flutter package for generating secure, auto-regenerating QR codes with encryption, digital signatures, and automatic expiration management.

Features #

  • 🔒 Secure by Design: Support for AES encryption and HMAC-SHA256 signatures
  • ⏱️ Auto-Expiration: Built-in validity duration management
  • 🔄 Auto-Regeneration: Automatic QR code refresh before expiration
  • 📦 Compact Payload Format: Optional CBOR + Base45 encoding for smaller, faster-to-scan QR codes
  • 📱 Flutter Integration: Ready-to-use Flutter widget
  • 🎨 Customizable Styling: Full control over QR code appearance
  • Performance Optimized: Efficient regeneration with minimal overhead

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  secure_qr_generator: ^1.1.0

Then run:

flutter pub get

Quick Start #

Basic Usage #

import 'package:secure_qr_generator/secure_qr_generator.dart';

// Create a configuration
final config = GeneratorConfig.production(
  secretKey: 'your-32-character-secret-key-here!!!',
  validityDuration: Duration(minutes: 5),
);

// Initialize the generator
final generator = SecureQRGenerator(config);

// Create QR data
final data = QRData(
  payload: {'userId': '123', 'access': 'granted'},
  metadata: {'purpose': 'access_control'},
  tags: ['entrance', 'visitor'],
);

// Generate a QR code
final result = await generator.generateQR(data);

Using the Auto-Regenerating Widget #

AutoRegeneratingQRView(
  data: data,
  generator: generator,
  size: 200,
  style: QrStyle(
    eyeStyle: QrEyeStyle(eyeShape: QrEyeShape.square),
    dataModuleStyle: QrDataModuleStyle(
      dataModuleShape: QrDataModuleShape.circle,
    ),
  ),
  onRegenerate: (result) {
    print('New QR generated: ${result.id}');
  },
  onError: (error) {
    print('Error: $error');
  },
)

Payload Format: Legacy vs. Compact #

Since version 1.1.0, the generator can emit two different QR payload formats, selected via GeneratorConfig.payloadFormat:

QrPayloadFormat.legacy (default) QrPayloadFormat.compact
Serialization JSON CBOR
Encoding Base64 Base45
Signature placement Embedded in JSON before encryption Appended as raw bytes, computed over the encrypted body (encrypt-then-MAC)
Typical QR density Baseline ~35–40% smaller for equivalent data
Understood by All versions of secure_qr_validator secure_qr_validator 1.2.0+ only
final config = GeneratorConfig(
  secretKey: 'your-32-character-secret-key-here!!!',
  enableEncryption: true,
  enableSignature: true,
  payloadFormat: QrPayloadFormat.compact, // opt in to the smaller format
);

Why this matters for scanning speed: Base45 lets the QR encoder use its alphanumeric mode (5.5 bits/character) instead of byte mode (8 bits/character), which Base64 content forces due to its lowercase letters and +///= characters. Combined with CBOR's more compact serialization, this typically produces a QR code with meaningfully fewer modules for the same data — easier and faster for a camera to read.

If your QR codes are scanned by other instances of your own app (rather than only by servers/terminals you control), don't hardcode payloadFormat: compact directly. Instead:

  1. Ship secure_qr_validator 1.2.0+ everywhere first — it transparently understands both formats, so this step is invisible to users.
  2. Once adoption of that validator version is effectively complete across your user base, drive payloadFormat from a remotely-controlled flag (feature flag / remote config) rather than a code constant, so you can flip it gradually and roll back instantly if needed.
  3. Only after the rollout is complete and confirmed via telemetry should you consider removing the legacy code path entirely.

Configuration Options #

Development Configuration #

final devConfig = GeneratorConfig.development();
// Uses QrPayloadFormat.compact by default — fine for development,
// since there's no store rollout to coordinate.

Production Configuration #

final prodConfig = GeneratorConfig.production(
  secretKey: 'your-secure-production-key-here!!!!!!',
  validityDuration: Duration(minutes: 5),
  payloadFormat: QrPayloadFormat.legacy, // default — override once ready
);

Custom Configuration #

final customConfig = GeneratorConfig(
  secretKey: 'your-secret-key',
  validityDuration: Duration(minutes: 10),
  enableEncryption: true,
  enableSignature: true,
  dataVersion: 1,
  idPrefix: 'CUSTOM_',
  payloadFormat: QrPayloadFormat.legacy,
);

Advanced Features #

Custom QR Code Styling #

QrStyle(
  eyeStyle: QrEyeStyle(
    eyeShape: QrEyeShape.square,
    color: Colors.blue,
  ),
  dataModuleStyle: QrDataModuleStyle(
    dataModuleShape: QrDataModuleShape.circle,
    color: Colors.black,
  ),
  embeddedImage: AssetImage('assets/logo.png'),
  embeddedImageStyle: QrEmbeddedImageStyle(
    size: Size(40, 40),
  ),
)

Custom Regeneration Interval #

AutoRegeneratingQRView(
  data: data,
  generator: generator,
  regenerationInterval: Duration(minutes: 2),
  // ... other parameters
)

Custom QR Code Builder #

AutoRegeneratingQRView(
  data: data,
  generator: generator,
  builder: (qrData) => Container(
    decoration: BoxDecoration(
      border: Border.all(color: Colors.blue),
    ),
    child: QrImageView(
      data: qrData,
      size: 200,
    ),
  ),
)

Error Handling #

The package includes comprehensive error handling:

try {
  final result = await generator.generateQR(data);
  // Use the result
} on GenerationError catch (e) {
  switch (e.type) {
    case GenerationErrorType.configuration:
      print('Configuration error: ${e.message}');
      break;
    case GenerationErrorType.encryption:
      print('Encryption error: ${e.message}');
      break;
    case GenerationErrorType.payloadTooLarge:
      print('Payload too large: ${e.message}');
      break;
    // Handle other error types...
  }
}

canEncodeData and estimateQRSize both take the currently configured payloadFormat into account, so checking data size ahead of generation reflects whichever format you have selected.

Security Considerations #

  • Keep your secretKey secure and never commit it to version control
  • Use different keys for development and production environments
  • Consider the QR code size limits when adding data
  • Choose an appropriate validity duration for your use case
  • Regularly rotate encryption keys in production
  • When switching payloadFormat to compact in a peer-to-peer scanning context, sequence the rollout so every reader supports the new format before any writer starts emitting it (see Staged rollout above)

Contributing #

Contributions are welcome! Please read our contributing guidelines before submitting pull requests.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

2
likes
160
points
17
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter package for generating secure, auto-regenerating QR codes with encryption, digital signatures, and automatic expiration management.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

base45, cbor, crypto, encrypt, flutter, qr_flutter

More

Packages that depend on secure_qr_generator