Skip to Content
New release 12 available 🎉
LicensingSubscription License

Subscription License with Encrypted Pro Code

A time-limited subscription license with a grace period, where the subscription-only code is protected with Babel Obfuscator Code Encryption.

Subscriptions need two behaviors that a plain expiry date does not give you: a grace period so paying customers are not cut off the instant a renewal is late, and enforcement that cannot be bypassed by editing a config file. This example does both, and ties the premium (“pro”) functionality to the subscription with Code Encryption: the pro method only runs while the subscription — including its grace window — is valid, because the Babel Virtual Machine gets its decryption password from the license.

Code Example

git clone https://github.com/babelfornet/subscription-license-console-example.git

ProSuite is a console application with a free basic feature and an encrypted pro feature; LicenseGenerator mints subscription licenses with configurable duration and grace.

Two Dates: Renewal and Hard Cutoff

The license carries two dates:

  • the engine-enforced ExpireDate, set to the end of the grace period (the hard cutoff), and
  • a soft subscription-end field marking when renewal is due.
DateTime subscriptionEnd = now.AddDays(days); // soft end — renewal due DateTime hardCutoff = subscriptionEnd.AddDays(grace); // engine-enforced end of grace var license = new StringLicense { ExpireDate = hardCutoff }; license .ForAssembly(assemblyFullName) .WithUniqueId("SUBSCR-") .WithHardwareKey(HardwareId.Create().ToMachineKey()) .WithField(Secrets.SubscriptionEndField, subscriptionEnd.ToString("O")) .WithField(Secrets.ProSource, Secrets.ProPassword.Encrypt(Secrets.FieldSecret)) .LicensedTo("Demo Customer", "demo@example.com", "ACME Corp");

Babel Licensing rejects the license automatically once ExpireDate has passed, so the hard cutoff needs no code of its own. The application only has to distinguish active from in grace, which it does by comparing the soft subscription-end field to the current time:

var now = DateTime.UtcNow; if (subEnd.HasValue && now > subEnd.Value) { int graceDaysLeft = (int)Math.Ceiling(((license.ExpireDate ?? now) - now).TotalDays); return new SubscriptionStatus(SubscriptionState.Grace, subEnd, graceDaysLeft, $"Subscription lapsed — grace period active ({graceDaysLeft} day(s) left). Please renew."); }

The Encrypted Pro Feature

The pro method is encrypted; its password comes from the license through the get password hook. That is what ties the encrypted code to the subscription: while the license validates (active or in grace) the hook returns the password and the method runs; once the hard cutoff passes, Validate() throws and the hook can no longer supply the password.

[Obfuscation(Feature = "msil encryption:internal=true;source=pro;password=Pr0-Su1te-2026-K3y", Exclude = false)] public static string Forecast(double[] series) { /* premium analytics */ } [Obfuscation(Feature = "msil encryption get password")] internal static string GetSourcePassword(string source) { var license = Validate(); // throws once past the end of grace var field = license.Fields.FirstOrDefault(f => f.Name == source) ?? throw new InvalidOperationException($"License does not grant source '{source}'."); return field.Value.Decrypt(Secrets.FieldSecret); }

Running It

# Build in Release — Babel encrypts Pro.Forecast. dotnet build src/ProSuite/ProSuite.csproj -c Release # Mint a subscription license: active for 30 days, 7-day grace. dotnet run --project src/LicenseGenerator -- --days 30 --grace 7 cp ProSuite.lic src/ProSuite/bin/Release/net8.0/ dotnet src/ProSuite/bin/Release/net8.0/ProSuite.dll

Re-mint the license to walk through every state:

dotnet run --project src/LicenseGenerator -- --days -2 --grace 7 # lapsed, in grace dotnet run --project src/LicenseGenerator -- --expired # past grace
StateConditionPro feature
Activebefore the subscription endruns
Gracepast the subscription end, before the hard cutoffruns, with a renewal warning
Expiredpast the hard cutofflocked — the BVM cannot decrypt it

Past the grace period the application proves the point by trying to call the pro method anyway:

Subscription expired: License expired Basic average: 13.63 Pro forecast is locked. Renew your subscription to restore access. (proof) encrypted Pro.Forecast blocked: License expired

For recurring billing, the same license is normally issued and renewed by the Babel Licensing Service, which can shorten the validity window and push renewals automatically. The offline file license shown here is the simplest way to demonstrate the active / grace / expired transitions.

keys.pem and the passwords in the sample are for demonstration only. Keep the RSA private key offline and issue licenses from the vendor side; only the public key ships with the application.

Last updated on