Skip to main content

ADR-002: Application Access Control for Vendors

Status

Proposed

Context

The photobooth web application is a commercial product sold to vendors. There is a business requirement to "lock" the application initially to prevent vendors from duplicating or reusing a single purchase across multiple unauthorized installations. The solution should provide a mechanism for our client to control access on a per-vendor basis.

Decision Drivers

  • Security: The mechanism must be effective at preventing unauthorized duplication.
  • Centralized Management: The client should be able to issue and manage access without needing to create custom builds for each vendor.
  • Vendor Experience: The unlocking process should be straightforward for the legitimate vendor.
  • Scalability: The solution should support a growing number of vendors.

Considered Options

Option 1: Static Passcode

A single, hard-coded password is used to unlock the application's administrative or customization features.

  • Pros:
    • Extremely simple and fast to implement.
  • Cons:
    • Highly insecure. A single leaked password compromises all vendor installations.
    • Does not prevent or track application duplication in any meaningful way.
    • Changing the password requires a new software deployment.

Option 2: Unique License Key with Local Validation

The client manually generates a unique license key for each vendor. This key is entered by the vendor upon first use and stored in the browser's localStorage. The application logic would then check for the presence and validity of this locally stored key on startup.

  • Pros:
    • No external server or internet dependency is required for the application to run after the initial setup.
    • More secure than a single static password, as each vendor has a unique key.
  • Cons:
    • Does not prevent duplication. A technically-inclined vendor could copy the application files along with the browser's local storage from a configured machine to a new one.
    • No mechanism for the client to revoke a key or see activation status.
    • Key generation and management is a manual process.

A central, client-controlled licensing server is created to manage license keys.

  • Activation Flow:

    1. The client generates a unique license key for a new vendor via a simple admin interface on the licensing server.
    2. The vendor receives the key and enters it into a dedicated activation screen in the photobooth application on first launch.
    3. The photobooth app sends an API request with the license key to the licensing server.
    4. The server validates the key. If it's valid and has not been used, it marks the key as "activated" and can associate it with an instance identifier. It then returns a success response (e.g., a JWT or a simple session token).
    5. The photobooth application stores the received token/confirmation and unlocks full functionality.
  • Pros:

    • Robust Security: Effectively prevents unauthorized duplication as each key can only be activated once.
    • Centralized Control: The client can issue, track, and potentially revoke licenses from a central dashboard.
    • Scalable: The system can easily manage hundreds or thousands of vendors.
  • Cons:

    • Increased Complexity: Requires the development and maintenance of a separate (though simple) backend service and database for the licensing server.
    • Internet Dependency: The photobooth application requires an internet connection for the one-time activation step. A graceful failure mode (e.g., a "could not connect" message) would be necessary.

Decision

We will proceed with Option 3: Unique License Key with Remote Validation Server, and we will specifically use the Cloudflare stack for the implementation (Workers, D1).

This choice provides a highly scalable and cost-effective solution that is well-suited for a serverless architecture. The Cloudflare stack fully supports the one-time activation model required for the offline-first PWA.

Consequences

The implementation will be built on the Cloudflare stack, which has the following consequences:

  • Backend Implementation:

    • A licenses table will be created in a Cloudflare D1 database to store license keys and their activation status. D1 is chosen over Workers KV for its strong consistency and transactional support, which is critical for preventing license reuse during an activation race condition.
    • A Cloudflare Worker will be developed to act as the API endpoint. It will handle the logic for validating a key against the D1 database, updating its status within a transaction, and issuing a signed JWT for offline use.
    • The JWT signing secret will be securely stored using Worker secrets.
  • Client Administration:

    • Unlike Supabase, Cloudflare D1 does not have a built-in GUI for database management that is suitable for a non-technical client.
    • Therefore, a new, simple admin web application must be built (e.g., using Cloudflare Pages). This application will be secured (e.g., by Cloudflare Access) and will provide the client with a simple interface to generate new license keys, which in turn calls a separate worker to update the D1 database.
  • Main Application:

    • The Next.js PWA's role remains the same: it will be modified to call the Cloudflare Worker URL for activation and store the resulting JWT for offline verification.
  • Hosting Plan & Operational Cost:

    • Cloudflare has a generous free tier for Workers and D1 that is likely sufficient for the low-traffic nature of this service, even in production.
    • A significant advantage for this use case is that Cloudflare's free tier does not pause projects for inactivity. This makes the free tier more viable for a low-traffic production service compared to other platforms. Usage should still be monitored to ensure it stays within the free limits as the client's business grows.