How to sign a License Service Message
It is not difficult to create an Entitlement Message. It is a JSON structure fully described in Axinom DRM Documentation.
To use an entitlement message with a license request, you need to wrap the entitlement message into a License Service Message and then create and sign the resulting JWT.
This article demonstrates how to do this in different programming languages.
Communication Keyโ
To sign the JWT you will need an Axinom DRM Communication Key (ID and the value, both are GUIDs). You get one when you request your Axinom DRM configuration. You can create additional Communication Keys using License Service Management API.
The values below are just examples:
const communicationKeyId = 'aa0151d7-081c-4699-a049-fc584556c9d2'
const communicationKeyAsBase64 = 'RPSdG/fViTkTjcuG3fcRXL2JDchGThWQ/tfSNHAoG+A='
Communication Key displayed in the DRM configuration on the Portal or provided in a configuration PDF-file is in the base64 format.
Entitlement Message and License Service Messageโ
For all examples below you need to create an Entitlement Message first and nest it into a License Service Message. Both are JSON structures, such as the ones below:
const keyId = '7459975d-b2f8-48ed-a325-56e4f34d19c7'
const entitlementMessage = {
type: 'entitlement_message',
version: 2,
content_keys_source: {
inline: [
{
id: keyId,
},
],
},
}
const licenseServiceMessage = {
version: 1,
com_key_id: communicationKeyId,
message: entitlementMessage,
}
Entitlement Message Toolโ
The easiest way to create and sign a License Service Message is to use Axinomโs Entitlement Message Tool.
Implementation in different languagesโ
In all examples below jwtAsString
is the resulting token which you can append to DRM license requests.
JavaScript (Node.js)โ
const jwt = require("jsonwebtoken");
...
let communicationKey = Buffer.from(communicationKeyAsBase64, "base64");
let jwtAsString = jwt.sign(licenseServiceMessage, communicationKey, {
"algorithm": "HS256",
"noTimestamp": true
});
Pythonโ
import jwt
import base64
...
communicationKey = base64.b64decode(communicationKeyAsBase64)
jwtAsString = jwt.encode(payload=licenseServiceMessage, key=communicationKey, algorithm='HS256')
PHPโ
use Firebase\JWT\JWT;
...
$communicationKey = base64_decode($communicationKeyAsBase64);
$jwtPayload = json_decode($licenseServiceMessage);
$jwtAsString = JWT::encode($jwtPayload, $communicationKey, 'HS256');
C#โ
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
...
var jwtPayload = JwtPayload.Deserialize(licenseServiceMessage);
var communicationKey = Convert.FromBase64String(communicationKeyAsBase64);
var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(communicationKey), "HS256");
var jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), jwtPayload);
var jwtAsString = new JwtSecurityTokenHandler().WriteToken(jwt);
There is also another sample how to generate license token message using C#.
Rustโ
use jsonwebtoken::{encode, Algorithm, EncodingKey, Header};
...
let jwtAsString = encode(
&Header::new(Algorithm::HS256),
&licenseServiceMessage,
&EncodingKey::from_base64_secret(communicationKeyAsBase64).unwrap(),
).unwrap();
Goโ
import (
"encoding/base64"
"github.com/golang-jwt/jwt"
)
...
// licenseServiceMessage should be a Go structure corresponding to the JSON object above
token := jwt.NewWithClaims(jwt.SigningMethodHS256, licenseServiceMessage)
communicationKey, _ := base64.StdEncoding.DecodeString(communicationKeyAsBase64)
jwtAsString, _ := token.SignedString(communicationKey)
C++โ
#include <iostream>
#include <jwt-cpp/jwt.h>
#include "jwt-cpp/traits/nlohmann-json/traits.h"
#include "jwt-cpp/base.h"
int main()
{
using traits = jwt::traits::nlohmann_json;
using claim = jwt::basic_claim<traits>;
nlohmann::json message = {
{"type", "entitlement_message"},
{"version", 2},
{"content_keys_source", {{"inline", {{{"id", "9eb4050d-e44b-4802-932e-27d75083e266"}, {"encrypted_key", "BPc9iaMPg4J6M7zokSDonA=="}}}}}}};
std::string communicationKeyAsBase64 = "YeujQgQjZoFNG6+N/+Uq30NH0oYWbHl33FnOvc9FBGk=";
std::string communicationKey = jwt::base::decode<jwt::alphabet::base64>(communicationKeyAsBase64);
auto token = jwt::create<traits>()
.set_type("JWT")
.set_payload_claim("version", 1)
.set_payload_claim("com_key_id", "fce7fd1a-a266-484a-be2e-b0530059934b")
.set_payload_claim("message", message)
.sign(jwt::algorithm::hs256(communicationKey));
std::cout << token << std::endl;
return 0;
}
JavaScript (Client-side)โ
This code shows how to calculate the HMAC-SHA256 without specific JWT library, with some generic cryptographic library, in this case with the old but gold Googleโs CryptoJS. This exact code is used by this Portalโs tools area, e.g by JWT-tool.
Never use the communication key on the client side in the end-userโs browser - for security reasons. Therefore, this sample has only limited usage. Use this approach only for fast prototyping/testing or in some admin-console UI logic.
<script
src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
...
var getToken = function (licenseServiceMessage , communicationKeyAsBase64) {
//The licenseServiceMessage input can be of type JSON string or JSON object
var licenseServiceMessageAsString = typeof licenseServiceMessage !== "string"
? JSON.stringify(licenseServiceMessage)
: licenseServiceMessage;
//Header
var header_b64_f = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9'; //constant
//Payload
var payload_b64 = CryptoJS.enc.Base64
.stringify(CryptoJS.enc.Utf8.parse(licenseServiceMessageAsString));
var payload_b64_f = payload_b64
.replace(/=+$/, '').replace(/\+/g, '-').replace(/\//g, '_');
//Signature
var secret_b64 = CryptoJS.enc.Base64.parse(communicationKeyAsBase64);
var hmacsha256 = CryptoJS.HmacSHA256(header_b64_f + '.' + payload_b64_f, secret_b64);
var hmacsha256_b64 = CryptoJS.enc.Base64.stringify(hmacsha256);
var hmacsha256_b64_f = hmacsha256_b64
.replace(/=+$/, '').replace(/\+/g, '-').replace(/\//g, '_');
//Return header.payload.signature JWT string aka license-token
return header_b64_f + "." + payload_b64_f + "." + hmacsha256_b64_f;
}
Swiftโ
To use the below code sample, import the https://github.com/kylef/JSONWebToken.swift library.
import JWT
...
var communicationKeyAsBytes = Data(base64Encoded: communicationKeyAsBase64)
let jwtAsString = JWT.encode(claims: licenseServiceMessage, algorithm: .hs256(communicationKeyAsBytes!))
Scalaโ
import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim, JwtHeader, JwtOptions}
import java.util.{Base64, HashMap, Map}
import java.nio.charset.StandardCharsets
...
val headers = """{"alg":"HS256","typ":"JWT"}"""
val communicationKey = new String(Base64.getDecoder.decode(communicationKeyAsBase64.getBytes()))
val token = pdi.jwt.Jwt.encode(headers, licenseServiceMessage, communicationKey, JwtAlgorithm.HS256)
Javaโ
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.io.IOException;
import java.util.Base64;
import java.util.Map;
import javax.crypto.SecretKey;
import java.util.HashMap;
...
String communicationKey = "Your_communicationkey";
ObjectMapper objectMapper = new ObjectMapper();
// licenseServiceMessage() should generate a JSON, corresponding to the JSON object above, using Java.
Map<String, Object> claims = objectMapper.readValue(licenseServiceMessage(), Map.class);
byte[] communicationKeyAsBytes = Base64.getDecoder().decode(communicationKey);
Map map = new HashMap<String,Object>();
map.put("alg","HS256");
map.put("typ","JWT");
SecretKey key = Keys.hmacShaKeyFor(communicationKeyAsBytes);
String token = Jwts.builder()
.header().add(map).and()
.claims().empty().add(claims).and()
.signWith(key,Jwts.SIG.HS256)
.compact();