License Regeneration
Regenerate license tokens to refresh features from the current tier configuration. This enables licenses to automatically receive new tier features without re-issuing.
When to Regenerate
- Tier features updated - When you add new features to a tier
- Key rotation - After rotating RSA keys, licenses need new tokens
- Feature sync - Ensure licenses have the latest feature set
- Self-renewal - Allow customers to refresh their own tokens
How It Works
When you regenerate a license token, Blackwalnut:
- Fetches the current feature set from the license's tier
- Merges tier features with any per-license custom features
- Generates a new JWT token with the updated features
- Preserves original installation_id, customer_id, tier, and expiration
- Updates the token's jti (JWT ID) and iat (issued at) claims
Tip: The lic_id claim
(license UUID) remains the same across regenerations, allowing you to track the same license
even after token updates.
Authentication Methods
The regenerate endpoint supports two authentication methods:
1. API Key Authentication (Admin)
Use a secret API key (sk_*) for server-side operations.
This method has full access and can regenerate any license.
$ curl -X POST /api/v1/apps/my-app/licenses/lic_abc123/regenerate \
-H "Authorization: Bearer sk_live_your_api_key" 2. License Token Authentication (Self-Renewal)
Provide the current license token in the request body. This enables end-user software to refresh its own license without exposing your API key.
$ curl -X POST /api/v1/apps/my-app/licenses/lic_abc123/regenerate \
-H "Content-Type: application/json" \
-d '{"current_token": "eyJhbGciOiJSUzI1NiIs..."}'' Important: When using license token authentication, the token must be valid, non-expired, and belong to the license being regenerated. Expired tokens cannot be used for self-renewal.
Use Case: Feature Updates
When you add a new feature to a tier, existing licenses don't automatically receive it. Use regeneration to update licenses with the new feature:
# 1. Original license has tier "pro" with features: ["api_access"]
# 2. You add "webhooks" feature to the "pro" tier
$ curl -X POST /api/v1/apps/my-app/tiers/pro/features \
-H "Authorization: Bearer sk_live_..." \
-d '{"name": "Webhooks", "slug": "webhooks"}'
# 3. Regenerate the license to get updated features
$ curl -X POST /api/v1/apps/my-app/licenses/lic_abc123/regenerate \
-H "Authorization: Bearer sk_live_..."
# Response - new token includes "webhooks"
{
"data": {
"token": "eyJhbGciOiJSUzI1NiIs...",
"features": ["api_access", "webhooks"]
}
} Use Case: Client-Side Refresh
Enable your software to refresh its license token without exposing your API key:
import requests
import jwt
class LicenseClient:
def __init__(self, app_slug, license_id, token):
self.app_slug = app_slug
self.license_id = license_id
self.token = token
self.base_url = "https://license.yourapp.com"
def refresh_token(self):
"""Refresh license to get latest tier features."""
url = f"{self.base_url}/api/v1/apps/{self.app_slug}/licenses/{self.license_id}/regenerate"
response = requests.post(url, json={"current_token": self.token})
if response.status_code == 200:
self.token = response.json()["data"]["token"]
return True
return False
def get_features(self):
"""Decode token and return features."""
# Note: Verify signature with public key in production
payload = jwt.decode(self.token, options={"verify_signature": False})
return payload.get("features", []) Custom Features Preservation
If a license has per-license custom features (beyond the tier's features), these are preserved and merged during regeneration:
- Tier features - Updated from current tier configuration
- Custom features - Preserved from the license record
- Result - Union of both sets in the new token
Example: License has custom feature ["custom_integration"].
Tier "pro" has ["api_access", "webhooks"].
Regenerated token features: ["api_access", "webhooks", "custom_integration"]
Error Handling
| Error | Cause | Solution |
|---|---|---|
401 Unauthorized | No authentication provided | Include API key or current_token |
400 Token Expired | current_token has expired | Use API key auth instead |
400 Token Mismatch | Token belongs to different license | Use correct license ID |
400 License Revoked | License has been revoked | Cannot regenerate revoked licenses |
400 Missing Tier | License's tier was deleted | Update license to a valid tier |
403 Forbidden | Used public key (pk_*) | Use secret key (sk_*) or license token |
Best Practices
- Implement automatic token refresh in your client software
- Refresh tokens periodically (e.g., daily) to get feature updates
- Cache the refreshed token locally to avoid unnecessary API calls
- Handle 400 errors gracefully - expired licenses cannot be refreshed
- Use license token auth for client-side refresh, API key for server-side bulk operations
- After key rotation, trigger regeneration for all active licenses