Skip to content
Adam Probert

Professional work · Platform · 2023

Gating a game launcher behind proof of purchase

Authorization-gated distribution for a studio's first premium title

What it was

The project

The studio's desktop launcher had been built for free-to-play games, so every download path in it assumed the content was free to take. Their first premium title changed that. I worked across the stack on authorization-gated distribution: entitlement checks in AWS Lambda before a download is issued, Akamai enforcing the same decision at the CDN so the files are not reachable by URL alone, and the TypeScript and React launcher refusing to offer the download until authorization comes back. The traffic shape drove as much of it as the security did: a premium unlock is a spike, not a curve, and the authorization path had to survive the whole player base arriving inside the same few minutes. Alongside it, a single-use voucher path so developers and beta testers could be let in without minting permanent entitlements.

Build

How it fits together

  • Entitlement verification in AWS Lambda, run before a download is issued rather than checked once it is already underway.
  • Sized the authorization path for launch day rather than for the average: at unlock the request rate goes from near nothing to the entire player base at once, then back again.
  • Kept the check itself small and stateless so it scales horizontally without coordination, with the bytes themselves never passing through it: Akamai carries the download, the backend only decides.
  • Akamai configured to gate the content at the delivery layer, so a leaked or guessed URL is not a download, and so the CDN absorbs the bandwidth spike that follows every authorization.
  • Authorization checks in the TypeScript and React launcher, keeping the download options closed until entitlement comes back, so a player gets a reason instead of a dead button.
  • A single-use voucher path for beta builds, granting temporary access to developers and testers without creating permanent entitlements that are awkward to withdraw.
  • The free-to-play path left exactly as it was, with the paid checks running beside it rather than replacing it.
Key decisions

The trade-offs that mattered

  • Three layers, on purpose

    Client, backend and CDN each fail differently, so each one covers what the others cannot. The redundancy is the design, not an oversight left in during review.

  • Lambda, for the shape of the traffic

    Download authorization is a short, stateless decision with a violently uneven load: at unlock time it is every player at once, and for most of the week it is close to idle. Lambda takes that shape without anyone provisioning for a peak that happens once, and without a fleet sitting warm and unused afterwards. The trade is cold starts, which we could accept on a request that is the prelude to a multi-gigabyte download nobody is timing to the millisecond.

  • Vouchers rather than entitlements for beta access

    Granting access is easy; taking it back is the part that shapes the system. Single-use codes expire on their own, so a beta cohort never becomes a permanent list somebody has to clean up later.

  • Do not touch the free-to-play path

    The existing games were live and working. Adding the paid checks alongside the free path, rather than generalising the free path to cover both, was the less elegant option and by a distance the easier one to be confident about.

Lesson learned

What I took from it

The instinct was to find the one correct place to enforce this, and there is no such place. The launcher is a Chromium app on the player's machine, so it enforces nothing that cannot be switched off. A backend check on its own still leaves the file sitting on a CDN for anyone holding the URL. CDN gating on its own leaves a player staring at a button that did nothing, with no idea why. Each layer is bypassable, unhelpful or both when it stands alone; three of them are a system. What surprised me was how much of the work was arguing for deliberate redundancy in a review culture that reads a second check as a wasted one. The argument that landed was not about attackers: it was that the layers do different jobs. The launcher explains, the backend decides, the CDN enforces.

Contact

Say hello.

Whether it’s work, something you’re stuck on, or a project you’re thinking about starting, I’m happy to chat through it.

Get in touch
  • Something you're building, or thinking about building
  • A problem you're stuck on and want another pair of eyes on
  • Anything on this site you want to know more about
  • A role or piece of work worth a conversation