Skip to main content

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='
note

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.

warning

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โ€‹

note

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();