runtime_keygen_sdk
Dart SDK for Keygen
Overview
Keygen is a fair source software licensing and distribution API. This package is meant to be used on the server and the client. Most actions in the Keygen API are supported.
Introduction to the Keygen API
Uses
This package will be useful for Dart applications that want to use Keygen for software licensing or distribution.
Supported platforms
All platforms that can use the http
package are supported.
Installation
To add runtime_keygen_sdk
to your Dart package, include it in your pubspec.yaml file:
dependencies:
runtime_keygen_sdk: ^1.0.0
Setup
In order to use the Dart SDK for Keygen, you must first create a Keygen account.
Follow the instructions for Getting Started and take note of your:
- Keygen AccountID
- Admin Email
- Admin Password
Example
Here is a pseudocode example of calling the Keygen API.
Note that this example will NOT work out-of-the-box.
KeygenClient client = KeygenClient('<accountId>');
KeygenLicensesApi licensesApi = KeygenLicensesApi(client);
License license = await licensesApi.createLicense(
token: token,
policy: policy,
user: user
);
Tests
Create a .env
file and place it in the root of the package.
The .env
file needs to contain the Keygen AccountID, Admin Email, and Admin Password, specified like this:
KEYGEN_ACCOUNTID=<accountid>
KEYGEN_ADMIN_EMAIL=<email>
KEYGEN_ADMIN_PASSWORD=<password>
Then you can run:
dart test
Why are there so many calls to await Future.delayed(wait);
in the tests?
Keygen enforces Rate Limiting and the delays are intended to prevent extraneous load.
These calls need to be in-between API calls; simply putting delays in setUp
and tearDown
is not sufficient.
Supported actions
Most actions in the Keygen API are supported, but not all.
The Keygen API can be divided into a few different categories:
Tokens are used by Keygen for authenticating API requests.
Products are used to segment policies and licenses, in the case where you sell multiple products. This allows you to keep licenses and policies between multiple products organized.
Entitlements can be attached to policies and to licenses to grant named "permissions" for things such as application features. Entitlements can be attached to the following resources:
- Policies: Any entitlement attached to a policy will automatically be attached to all licenses which implement the given policy.
- Licenses: Entitlements attached to a license are one-off and only apply to that specific license resource.
- Releases: Entitlements can be attached to releases through constraints, in order to assert that a given licensee possesses the necessary entitlements before being allowed to access a release's artifacts.
Policies define the different "types" of licenses that your product offers. Policies can be for a number of different things, from different "tiers" for your product (e.g. Basic vs Pro) to fine-grained feature policies.
Users represent an identity for an end-user, or licensee, of your software.
Licenses are used to grant access to your software. Each license resource will implement a policy, which will define the "rules" which that license must follow to remain valid. Each license can be associated with a user, but that's optional; this is useful when you're associating multiple licenses with a single user.
Machines can be used to track and manage where your users are allowed to use your product.
There are other less common categories as well:
- Components
- Environments
- Processes
- Distribution
Components are hardware components for machines.
Environments can be created to segment your Keygen resources into buckets, for example, for an isolated sandbox environment, or a shared production environment.
Processes are concurrent processes across machines.
Distribution is the distribution and updating of software via Keygen.
Below are tables that outline which actions are implemented for each category, as well as what tests exist and where the actions fit in the Client / Server dichotomy.
TLDR:
- User actions and License actions (except validating and checking-in) will run on server-side.
- License validating, license checking-in, and Machine actions will run on client-side.
NOTE: Not every action will be executed client-side or server-side. Some actions (e.g. createProduct
) are only
executed during initial setup and are not executed during regular client / server interaction.
Token Actions | Implemented | Tests | Client / Server |
---|---|---|---|
createToken | ✅ | ✅ | |
retrieveToken | ✅ | ✅ | |
regenerateToken | ✅ | ✅ | |
revokeToken | ✅ | ✅ | |
listTokens | ✅ | ✅ |
Product Actions | Implemented | Tests | Client / Server |
---|---|---|---|
createProduct | ✅ | ✅ | One time only |
retrieveProduct | ✅ | ✅ | |
updateProduct | ✅ | ✅ | |
deleteProduct | ✅ | ✅ | |
listProducts | ✅ | ✅ | |
createProductToken | ✅ | ✅ |
Entitlement Actions | Implemented | Tests | Client / Server |
---|---|---|---|
createEntitlement | ✅ | ✅ | One time only |
retrieveEntitlement | ✅ | ✅ | |
updateEntitlement | ✅ | ✅ | |
deleteEntitlement | ✅ | ✅ | |
listEntitlements | ✅ | ✅ |
Policy Actions | Implemented | Tests | Client / Server |
---|---|---|---|
createPolicy | ✅ | ✅ | One time only |
retrievePolicy | ✅ | ✅ | |
updatePolicy | ✅ | ✅ | |
deletePolicy | ✅ | ✅ | |
listPolicies | ✅ | ✅ | |
attachPolicyEntitlements | ✅ | ✅ | |
detachPolicyEntitlements | ✅ | ✅ | |
listEntitlements | ✅ | ✅ |
User Actions | Implemented | Tests | Client / Server |
---|---|---|---|
createUser | ✅ | ✅ | |
retrieveUser | ✅ | ✅ | |
updateUser | ✅ | ✅ | |
deleteUser | ✅ | ✅ | |
listUsers | ✅ | ✅ | |
updatePassword | ✅ | ✅ | |
resetPassword | ✅ | 📧 | |
banUser | ✅ | ✅ | |
unbanUser | ✅ | ✅ | |
createUserToken | ✅ | ✅ | |
changeGroup | ❌ | ❌ | ❌ |
addSecondFactor | ❌ | ❌ | ❌ |
retrieveSecondFactor | ❌ | ❌ | ❌ |
updateSecondFactor | ❌ | ❌ | ❌ |
deleteSecondFactor | ❌ | ❌ | ❌ |
listSecondFactors | ❌ | ❌ | ❌ |
License Actions | Implemented | Tests | Client / Server |
---|---|---|---|
createLicense | ✅ | ✅ | Server |
retrieveLicense | ✅ | ✅ | Server |
updateLicense | ✅ | ✅ | Server |
deleteLicense | ✅ | ✅ | Server |
listLicenses | ✅ | ✅ | Server |
validateLicenseByID | ✅ | ✅ | |
validateLicenseByKey | ✅ | ✅ | Client |
suspendLicense | ✅ | ✅ | Server |
reinstateLicense | ✅ | ✅ | Server |
renewLicense | ✅ | ✅ | Server |
revokeLicense | ✅ | ✅ | Server |
checkOutLicense | ❌ | ❌ | ❌ |
checkInLicense | ✅ | ✅ | Client |
incrementUsage | ❌ | ❌ | ❌ |
decrementUsage | ❌ | ❌ | ❌ |
resetUsage | ❌ | ❌ | ❌ |
createLicenseToken | ✅ | ✅ | Server |
attachUsers | 🐛 | 🐛 | Server |
detachUsers | 🐛 | 🐛 | Server |
listUsers | 🐛 | 🐛 | Server |
attachEntitlements | ✅ | ✅ | Server |
detachEntitlements | ✅ | ✅ | Server |
listEntitlements | ✅ | ✅ | Server |
changeLicensePolicy | ✅ | ✅ | Server |
changeOwner | ❌ | ❌ | ❌ |
changeGroup | ❌ | ❌ | ❌ |
Machine Actions | Implemented | Tests | Client / Server |
---|---|---|---|
activateMachine | ✅ | ✅ | Client |
retrieveMachine | ✅ | ✅ | Client |
updateMachine | ✅ | ✅ | Client |
deactivateMachine | ✅ | ✅ | Client |
listAllMachines | ✅ | ✅ | Client |
checkOutMachine | ❌ | ❌ | ❌ |
pingHeartbeat | ✅ | ✅ | Client |
resetHeartbeat | ✅ | ✅ | Client |
changeOwner | 🐛 | 🐛 | Server |
changeGroup | ❌ | ❌ | ❌ |
Miscellaneous Actions | Implemented | Tests | Client / Server |
---|---|---|---|
whoAmI | 🐛 | 🐛 | Client / Server |
forgotPassword | ✅ | 📧 |
Legend
🐛 = bug in generated OpenAPI code from runtime_keygen_openapi
package
whoAmI currently throws exception when called with license token or product token.
license attachUsers is currently missing from OpenAPI .yml file from runtime_keygen_openapi
package.
license detachUsers is currently missing from OpenAPI .yml file from runtime_keygen_openapi
package.
license listUsers is currently missing from OpenAPI .yml file from runtime_keygen_openapi
package.
machine changeOwner is currently missing from OpenAPI .yml file from runtime_keygen_openapi
package.
❌ = not planned to be supported (but may be re-evaluated)
📧 = requires reading email
The remaining groups of actions are not supported:
- Components: not yet specified in OpenAPI spec file
- Environments: not planned to be supported (but may be re-evaluated)
- Processes: not planned to be supported (but may be re-evaluated)
- Distribution: not planned to be supported (but may be re-evaluated)
Workflows
There are several common scenarios when using Keygen. These involve interacting with the client application, possibly some intermediary server, possibly the user's email, and Keygen itself.
One time:
Various actions may only need to be done once, and may be done from the Keygen dashboard.
Some of these actions are:
- Create a product
- Create entitlements
- Create a policy
When creating a policy, you may want to specify the strategy to use for matching components. You can do that with these attributes:
requireComponentsScope = true
componentMatchingStrategy = MATCH_ANY, MATCH_TWO, MATCH_MOST, MATCH_ALL
Workflow: Creating a license
Pseudocode for the client application would be:
1. start the application with no license key
2. send user credentials to intermediary server, and ask to create a new license
3. application receives license key from intermediary server
4. application stores license key
Pseudocode for the intermediary server would be:
1. receive request from application to create license
2. contact Auth0 to obtain user_id
3. send /createLicense request to Keygen
4. receive response from Keygen with license key and license id
5. send /updateLicense request to Keygen, with license id and Auth0 user_id to store in metadata
6. send license key to application
Workflow: Activating a machine
Pseudocode for the client application would be:
1. get machine id and other component fingerprints
2. ask intermediary server to activate the machine, and send license key and component fingerprints
3. receive response from intermediary server that machine is activated
Pseudocode for the intermediary server would be:
1. receive request from application to activate machine with various fingerprints
2. send /whoAmI to Keygen with license key
3. receive license id
4. send /activateMachine to Keygen with license id and machine fingerprint
5. receive machine id
6. send /addComponent to Keygen with machine id and component fingerprints
7. send machine activation to application
Workflow: Validating a license
Pseudocode for the client application would be:
1. determine that it is time to validate license
2. send request to validate to intermediary server, with license key and fingerprints
3. receive validation from server
Pseudocode for the intermediary server would be:
1. receive request for validation from application, with license key and fingerprints
2. send /validateLicenseKey to Keygen, with license key and fingerprints
3. receive validation from Keygen
4. send validation to application
Caveats
Updating metadata
Since the metadata attribute is simply a key-value store (object), all write operations will overwrite the entire object, so be sure to merge existing data on your end when performing updates.
Metadata is not inheritable.
https://keygen.sh/docs/api/metadata/
https://github.com/orgs/keygen-sh/discussions/106
Implementation details
Modifications from generated OpenAPI code
This package uses runtime_keygen_openapi
, which includes generated OpenAPI code.
OpenAPI defines some parameters as Object? metadata
, but these have been modified to be Map<String, String>? metadata
.
OpenAPI defines some parameters as Object? page
, but these have been modified to be Map<String, int>? page
.
Libraries
- runtime_keygen_sdk
- runtime_keygen_sdk