-
Notifications
You must be signed in to change notification settings - Fork 263
Creating Signed Assertions
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.
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
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.
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.
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.
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.