Skip to content
This repository has been archived by the owner on Aug 22, 2019. It is now read-only.

Creating Signed Assertions

SueSmith edited this page Sep 29, 2014 · 3 revisions

If you are issuing Open Badges, you can define your badge assertions either as hosted files or as JSON Web Signatures. This tutorial will guide you through the process of generating a signed assertion, which you can then use, for example, with the Issuer API.

If you're new to assertions, check out the current spec and Assertion Information for the Uninitiated. To create a signed assertion, you need to define the three elements in JSON structures as you do for hosted assertions - check out the Badge Lab Tutorial if you don't have your JSON prepared yet.

Assertions involve three files: the badge assertion, the badge class and the issuer organization. With a hosted assertion, these three files are hosted at stable URLs, with the badge assertion including a link to the badge class, which in turn includes a link to the issuer organization. With a signed assertion, the badge class and issuer organization files are still stored at URLs, but the badge assertion itself is instead packaged into a JSON Web signature.

The sample code below will demonstrate signing a badge assertion in node.js.

Contents

Overview

To create a signed badge, issuers should:

  • have the relevant badge class and issuer JSON files hosted
  • prepare a private key for signing
  • host a corresponding public key for verification
  • create a badge assertion in JSON within your application code
  • this should include the public key URL in the verify object
  • sign the assertion using the private key
  • validate your assertion signature

Prepare your assertion

The badge assertion itself is what represents a specific badge awarded to a specific earner. The JSON structures for it can be built in your application code.

Your signed assertion will also require a hosted badge class and issuer organization. These correspond to the generic badge (defining the skill or achievement) and the awarding organization - they should be stored at stable URLs.

Prepare your badge class and issuer organization files and store them online - see the following examples:

badge-class.json:

{
  "name": "Amazing Badge",
  "description": "For doing amazing things.",
  "image": "https://example.org/amazing-badge.png",
  "criteria": "https://example.org/amazing-badge/criteria.html",
  "issuer": "https://example.org/issuer-organization.json",
  "alignment": [ ]
}

issuer-organization.json

{
  "name": "Excellent Badge Issuer",
  "image": "https://example.org/issuer.png",
  "url": "https://issuersite.org"
}

Prepare the badge assertion JSON in your site or application code as follows:

var assertion = {

    "uid": "abcdefghijklm1234567898765",
    "recipient": {
        "identity": "sha256$a1b2c3d4e5f6g7h8i9a1b2c3d4e5f6g7h8i9a1b2c3d4e5f6g7h8i9",
        "type": "email",
        "hashed": true
    },
    "badge": "http://issuersite.org/badge-class.json",
    "verify": {
        "url": "http://issuersite.org/public-key.pem",
        "type": "signed"
    },
    "issuedOn": 1403120715

};

Notice that the badge assertion links to badge-class.json, which links to issuer-organization.json.

If you have used hosted assertions already, you may also notice that the verify section is different. The type is signed rather than hosted and the url points to the public key that will be used to verify the signed assertion.

Prepare your keys

You will use a private key to sign your assertion, which includes a field linking to the corresponding public key as we saw above. You can generate the keys to use an RSA algorithm in a terminal as in the following example:

openssl genrsa -out private-key.pem 1024

You can then extract the public key from this as follows:

openssl rsa -in private-key.pem -out public-key.pem -outform PEM -pubout

The two keys should now be accessible in the current directory. You will use the private key within your own application code, to sign the assertion, and the public key should be placed at the location you specify in your assertion JSON verify.url field.

Sign the assertion

You can now use your private key to sign the assertion JSON. The following example demonstrates a simple node.js app, which uses JWS to sign the assertion with an RSA-SHA256 algorithm:

var express = require("express");
var app = express();
var jws = require('jws');
var fs = require('node-fs');

app.get('/', function(req, res) {

	//prepare the assertion
	var assertion = {

		"uid": "abcdefghijklm1234567898765",
		"recipient": {
			"identity": "sha256$a1b2c3d4e5f6g7h8i9a1b2c3d4e5f6g7h8i9a1b2c3d4e5f6g7h8i9",
			"type": "email",
			"hashed": true
		},
		"badge": "http://issuersite.org/badge-class.json",
		"verify": {
			"url": "http://issuersite.org/public-key.pem",
			"type": "signed"
		},
		"issuedOn": 1403120715

	};

	//sign the assertion
	const signature = jws.sign({
		header: {alg: 'rs256'},
		payload: assertion,
		privateKey: fs.readFileSync(__dirname + '/private-key.pem')
	});
	//for demonstration, write the signature to the browser
	res.send(signature);
});

var port = Number(process.env.PORT || 5000);
app.listen(port, function() {
	console.log("Listening on " + port);
});

In this case the private key is in the same directory as the app. The example simply writes the JSON Web Signature string out to the browser for demonstration - in your own apps you will naturally use the signature string, for example to push the badge to the earner Backpack.

The signature has the following structure:

abcdeFGHIJ12345.abcdeFGHIJ12345abcdeFGHIJ12345._abcdeFGHIJ12345-abcdeFGHIJ12345

This example is simplified, but the string includes three sections separated by the . character: the header, the payload and the signature itself.

Check the assertion

You can pass your signature string to the Validator to test it.

The signature string should include the badge assertion as payload, which you can check in a node.js app as follows:

var decoded = jws.decode(signature);
console.log(decoded.payload);//output assertion

You can also check that it validates using the public key in your app as follows:

var publicKey=fs.readFileSync(__dirname + '/public-key.pem');
var verified=jws.verify(signature, publicKey);
console.log(verified);//true if verifies, false otherwise

See the assertion spec for more on verification.

Clone this wiki locally