How to Prevent License Key Sharing
A license key, on its own, is just a string of characters. Nothing stops someone from posting a valid one in a forum thread or a Discord server unless the system checking that key actually does something about it. PermitCore uses three separate, complementary techniques — none of them alone is bulletproof, but together they make casual key-sharing genuinely inconvenient.
Every activation is logged per device — the first place you'd notice a key being used more widely than expected.
1. Node-Locking: Tie a Key to a Device
Every license has a Max Activations limit — how many distinct devices it can be active on at once. When node-locking is on, the first activate() call binds the key to a hardware fingerprint (a hash derived from stable machine identifiers, not anything personally identifying). A second machine trying to activate the same key is simply rejected once that limit is reached — reactivating on the same device again doesn't consume a fresh seat, but a genuinely different machine does.
This is the first line of defense: sharing a key with a friend costs one of your own activation seats the moment they use it, and once the limit is hit, both of you find out immediately. See Activating a License on a Device for exactly how the fingerprinting works.
2. Floating Licenses: Shared Seats, Not Shared Copies
For team products where node-locking doesn't fit — say, a license meant to float across whoever on a team is actively using the software right now — PermitCore supports floating/concurrent licenses instead. A fixed number of concurrent sessions are checked out and released as people start and stop using the app; once every seat is checked out, the next activation attempt is rejected until someone else checks theirs back in.
This still bounds simultaneous use to what was actually paid for — it just does it per-concurrent-session instead of per-permanent-device.
3. Abuse Detection: Catching the Pattern Node-Locking Misses
Here's the gap the first two techniques don't cover: a key with a generous seat count (say, a 50-seat team license) can still be posted publicly and used by many more than 50 different people over time, as long as no more than 50 are active at any single moment. Every individual request still looks legitimate.
PermitCore's LicenseAbuseDetectionService watches for this pattern directly — tracking, per license key, how many distinct caller IP addresses hit validate()/activate() within a rolling one-hour window:
private const int RequestSuspiciousThreshold = 200; // requests/hour private const int RequestBlockThreshold = 2000; // requests/hour private const int IpFanoutSuspiciousMultiplier = 5; // × MaxActivations private const int IpFanoutSuspiciousFloor = 20; // distinct IPs/hour, minimum private const int IpFanoutBlockMultiplier = 20; // × MaxActivations private const int IpFanoutBlockFloor = 100; // distinct IPs/hour, minimum
The threshold scales with the license's own seat count — a 1-seat license reaching 20 distinct IPs in an hour is already abnormal, while a 500-seat license needs proportionately more before it's flagged. Two tiers:
- Suspicious — the request is still served (a real customer isn't blocked over a false positive), but PermitCore logs an audit entry and fires a
license.abuse_suspectedwebhook so you can decide what to do, at most once per key per hour. - Block — well past the suspicious threshold, the request is rejected outright with no database work performed, protecting your infrastructure from a key that's clearly being hammered from everywhere.
What This Doesn't Stop
Being direct about the limits: none of this stops someone determined to reverse-engineer your binary and patch out the license check entirely — that's a different problem, outside what any server-side licensing system can solve on its own. What these three techniques together actually solve is the far more common case: a valid key quietly circulating beyond the people who paid for it. Node-locking and floating limits bound how much simultaneous use one key can support; abuse detection catches the pattern when a key gets shared more widely than its seat count alone would reveal.