-
Notifications
You must be signed in to change notification settings - Fork 1
OB2 vs OB3
openbadgeslib supports two generations of the IMS Global Open Badges specification side by side. This page explains what each one is, when to pick which, how they interoperate, and how the -V flag and the Python packages select between them.
OB 2.0 builds a JSON Assertion payload (recipient's SHA-256 hashed email plus salt, badge metadata URLs, issuance timestamp) and signs it with the issuer's private key using JWS compact serialisation (RS256 for RSA, ES256 for ECC). The resulting token is baked directly into the badge image:
-
SVG — an
<openbadges:assertion verify="…"/>XML element -
PNG — an
iTXtchunk with keywordopenbadges
Recipient identity is hashed (SHA-256 + salt), so the email is not stored in clear text. Verification re-hashes the supplied email and compares it. OB 2.0 also supports expiration and revocation-list checking.
The implementation lives in openbadgeslib.ob2 (with top-level badge, signer, verifier modules kept as backward-compatible shims). See Python API OB2.
OB 3.0 models the badge as a W3C Verifiable Credential using the VC 2.0 data model and signs it as a JWT-VC (PyJWT, RS256/ES256). The credential is an OpenBadgeCredential with structured Issuer, Achievement, and credentialSubject objects.
Key data-model details from openbadgeslib/ob3/credential.py:
-
@contextis["https://www.w3.org/ns/credentials/v2", "https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json"] -
typeis["VerifiableCredential", "OpenBadgeCredential"] - Dates use VC 2.0 field names
validFrom/validUntil(VC 1.1issuanceDate/expirationDateare still accepted on read) - The credential
idauto-generates asurn:uuid:…when absent - The recipient (
recipient_id/credentialSubject.id) is eithermailto:email@example.comor a DID — it is not hashed - The JWT wrapper carries
iss(issuer id),sub(recipient),jti,iat, and optionalexp;OB3Verifier.verify()cross-checks these claims against the credential body
The credential can also be baked into SVG/PNG images using the same carrier format as OB 2.0. The implementation lives in openbadgeslib.ob3. See Python API OB3.
| Aspect | OpenBadges 2.0 | OpenBadges 3.0 |
|---|---|---|
-V value |
2 (default) |
3 |
| Token format | JWS compact serialisation | JWT-VC |
| Data model | OB 2.0 Assertion | W3C Verifiable Credentials 2.0 |
| Python package | openbadgeslib.ob2 |
openbadgeslib.ob3 |
| Core classes |
Badge, Signer, Verifier
|
OpenBadgeCredential, Issuer, Achievement, OB3Signer, OB3Verifier
|
| Recipient identity | SHA-256 hashed email (+ salt) |
mailto: URI or DID, in clear |
| Date fields | issuance + expiration in assertion |
validFrom / validUntil
|
| Algorithms | RS256 / ES256 (RSA 2048, ECC P-256) | RS256 / ES256 (RSA 2048, ECC P-256) |
| Image baking | SVG <openbadges:assertion>, PNG iTXt
|
same SVG/PNG carrier format |
| Revocation list | yes | not modelled |
The four versioned CLI tools — openbadges-keygenerator, openbadges-signer, openbadges-verifier, openbadges-publish — accept the -V {2,3} flag to select the specification version. The default is 2. (openbadges-init has no -V flag.)
# Sign as OpenBadges 2.0 (default — -V 2 is implied)
openbadges-signer -c ./config/config.ini -b 1 -r recipient@example.com -o /tmp/
# Sign as OpenBadges 3.0
openbadges-signer -c ./config/config.ini -b 1 -r recipient@example.com -o /tmp/ -V 3
# Verify an OB 2.0 badge (recipient re-hashed against the assertion)
openbadges-verifier -i /tmp/badge_1_recipient@example.com.svg -r recipient@example.com
# Verify an OB 3.0 badge, supplying the PEM public key directly with -k
openbadges-verifier -i /tmp/badge_1_recipient@example.com.svg -r recipient@example.com \
-V 3 -k ./config/keys/verify_rsa_key_1.pemIn Python, you choose the version simply by importing from the matching package:
# OpenBadges 2.0
from openbadgeslib.ob2 import Badge, Signer, Verifier
# OpenBadges 3.0
from openbadgeslib.ob3 import (
Issuer, Achievement, OpenBadgeCredential,
OB3Signer, OB3Verifier,
)For the full signing and verification workflow shared by both versions, see Signing and Verification.
Choose OB 2.0 when you need to interoperate with the large existing ecosystem of Open Badges 2.0 backpacks, displayers and verifiers, or when you want the recipient's email kept as a salted hash rather than in clear text inside the credential.
Choose OB 3.0 when you want the modern W3C Verifiable Credentials data model — DID-based recipients, structured issuer/achievement metadata, and alignment with the broader VC tooling ecosystem — or when a consumer specifically requires JWT-VC credentials.
-
Same crypto, same images. Both versions use the same key types (RSA 2048 / ES256 P-256 keys generated by
openbadges-keygenerator) and bake into the same SVG and PNG carrier format, so the image pipeline is shared. A single PEM key pair can serve either version. -
The token inside differs. An OB 2.0 image carries a JWS assertion; an OB 3.0 image carries a JWT-VC. A verifier must use the matching
-Vvalue (or the matchingOB2/OB3Verifier class) — there is no automatic cross-format detection. -
OB 3.0 reads older VC fields. On verification, OB 3.0 accepts both VC 2.0 (
validFrom/validUntil) and VC 1.1 (issuanceDate/expirationDate) field names, but always writes the VC 2.0 names. -
Recipient binding differs. OB 2.0 compares a SHA-256 hash of the supplied email; OB 3.0 binds to a
mailto:URI or DID andOB3Verifier.verify()accepts an optionalexpected_recipientto assert it.
See also Signing and Verification for the end-to-end flows, Python API OB2 and Python API OB3 for the programmatic interfaces.
openbadgeslib · LGPLv3 (library) / BSD (CLI) · Issues
Getting Started
Concepts
Reference
Guides
Project