Skip to content

Instantly share code, notes, and snippets.

@ezekg
Last active May 13, 2021 15:47
Show Gist options
  • Save ezekg/91bfab64e2572b949cae7166557ab95e to your computer and use it in GitHub Desktop.
Save ezekg/91bfab64e2572b949cae7166557ab95e to your computer and use it in GitHub Desktop.
How to integrate 2Checkout with Keygen for license key creation. NOTE: Remember to set the following env vars: KEYGEN_PRODUCT_TOKEN, KEYGEN_ACCOUNT_ID and KEYGEN_POLICY_ID.

Usage

To generate a license and activation token, perform a GET request to the script, passing in an order query parameter.

curl -vg -X GET 'http://localhost:3000?order=1'

⚠️ Further Development ⚠️

You should modify the validation steps for the given order ID query parameter. You should utilize your payment system's API to verify that the order ID is for a valid order, to prevent bad actors from generating unauthorized license keys. E.g. if you're using 2Checkout, utilize the 2Checkout API to validate that the order ID does indeed exist.

Local Testing

First up, add the contents of this example into a file called index.php.

Next, configure a few environment variables:

# Keygen product token (don't share this!)
export KEYGEN_PRODUCT_TOKEN="YOUR_KEYGEN_PRODUCT_TOKEN"

# Your Keygen account ID
export KEYGEN_ACCOUNT_ID="YOUR_KEYGEN_ACCOUNT_ID"

# The Keygen policy to use when creating licenses for new users
export KEYGEN_POLICY_ID="YOUR_KEYGEN_POLICY_ID"

You can either run each line above within your terminal session before starting the app, or you can add the above contents to your ~/.bashrc file and then run source ~/.bashrc after saving the file.

Next, start a local PHP server in the directory you placed the index.php file:

php -S localhost:3000

Then perform a GET request to the local server:

curl -vg -X GET 'http://localhost:3000?order=1'

You should then see output from the script.

<?php
// These are required environment variables!
define('KEYGEN_PRODUCT_TOKEN', getenv('KEYGEN_PRODUCT_TOKEN'));
define('KEYGEN_ACCOUNT_ID', getenv('KEYGEN_ACCOUNT_ID'));
define('KEYGEN_POLICY_ID', getenv('KEYGEN_POLICY_ID'));
// Since this page should only be accessed after a successful order redirect,
// we should verify that the passed order is valid -- this helps defend
// against somebody accessing this page directly to generate free
// license keys.
//
// NOTE: You should use this to check if the given order ID is valid before
// continuing onto the license generation! E.g. if you're using 2Checkout,
// utilize the 2Checkout API to validate the order ID.
if (!isset($_GET['order'])) {
http_response_code(400);
echo "Order ID is required for generating new licenses\n";
exit(1);
}
function create_license() {
$ch = curl_init(
sprintf("https://api.keygen.sh/v1/accounts/%s/licenses", KEYGEN_ACCOUNT_ID)
);
$body = json_encode([
'data' => [
'type' => 'license',
'attributes' => [
// NOTE: Hash the order ID to ensure duplicate licenses cannot be generated
'key' => hash('sha256', $_GET['order']),
// Store order ID in the license's metadata
'metadata' => [
'orderId' => $_GET['order']
]
],
'relationships' => [
'policy' => [
'data' => ['type' => 'policy', 'id' => KEYGEN_POLICY_ID]
]
]
]
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
sprintf('Authorization: Bearer %s', KEYGEN_PRODUCT_TOKEN),
'Content-Type: application/json',
'Accept: application/json'
]);
$res = curl_exec($ch);
$license = json_decode($res);
// Check if we received an error from Keygen
if (isset($license->errors)) {
http_response_code(500);
$messages = join(', ', array_map(function($err) { return "{$err->title}: {$err->detail}"; }, $license->errors));
echo "Keygen license creation error: $messages\n";
exit(1);
}
return $license->data;
}
function create_activation_token($license) {
$ch = curl_init(
sprintf("https://api.keygen.sh/v1/accounts/%s/licenses/%s/tokens", KEYGEN_ACCOUNT_ID, $license->id)
);
$body = json_encode([
'data' => [
'type' => 'token',
'attributes' => [
'maxActivations' => 3,
'maxDeactivations' => 2
]
]
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
sprintf('Authorization: Bearer %s', KEYGEN_PRODUCT_TOKEN),
'Content-Type: application/json',
'Accept: application/json'
]);
$res = curl_exec($ch);
$token = json_decode($res);
// Check if we received an error from Keygen
if (isset($token->errors)) {
http_response_code(500);
$messages = join(', ', array_map(function($err) { return "{$err->title}: {$err->detail}"; }, $token->errors));
echo "Keygen activation token creation error: $messages\n";
exit(1);
}
return $token->data;
}
// Create the license and activation token
$license = create_license();
$token = create_activation_token($license);
// TODO: Generate distribution download link. Then email link, license key and
// activation token to the customer.
echo "Keygen: created license {$license->id} and activation token {$token->id}\n";
echo " License key: {$license->attributes->key}\n";
echo " Activation token: {$token->attributes->token}\n";
http_response_code(202);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment