Mosaic products documentation: Concepts, API Reference, Technical articles, How-to, Downloads and tools

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

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 "jwt-cpp/jwt.h"
#include "cpp-base64/base64.cpp"
...
string communicationKey = base64_decode(communicationKeyAsBase64, false);
string jwtAsString = jwt::create().set_type("JWT").set_payload_claim("licenseServiceMessage", licenseServiceMessage).sign(jwt::algorithm::hs256(communicationKey));

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