Skip to content

Signing & Verification ​

badges.ninja publishes a public cryptographic identity so third parties can verify credentials that carry a digital signature. This is the foundation for Open Badges 3.0 / W3C Verifiable Credentials support.

These endpoints are public and require no authentication. They are relative to https://api.badges.ninja.

Issuer DID ​

The platform's issuer identity is the did:web identifier:

did:web:api.badges.ninja

By the did:web rules, this resolves to the DID document served at the well-known path below.

DID Document ​

GET /.well-known/did.json

Returns the DID document exposing the issuer's public signing key (an Ed25519 JsonWebKey2020) as its assertionMethod.

bash
curl https://api.badges.ninja/.well-known/did.json
json
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/jws-2020/v1"
  ],
  "id": "did:web:api.badges.ninja",
  "verificationMethod": [
    {
      "id": "did:web:api.badges.ninja#<kid>",
      "type": "JsonWebKey2020",
      "controller": "did:web:api.badges.ninja",
      "publicKeyJwk": { "kty": "OKP", "crv": "Ed25519", "x": "<base64url>" }
    }
  ],
  "assertionMethod": ["did:web:api.badges.ninja#<kid>"],
  "authentication": ["did:web:api.badges.ninja#<kid>"]
}

Response content type is application/did+json. The document is cacheable (it changes only on key rotation).

JWKS ​

For verifiers that prefer JWK Set discovery over DID resolution:

GET /.well-known/jwks.json
bash
curl https://api.badges.ninja/.well-known/jwks.json
json
{
  "keys": [
    {
      "kty": "OKP",
      "crv": "Ed25519",
      "x": "<base64url>",
      "kid": "<thumbprint>",
      "alg": "EdDSA",
      "use": "sig"
    }
  ]
}

The kid is the RFC 7638 thumbprint of the public key and matches the fragment on the DID document's verificationMethod id.

Verifiable Credential (Open Badges 3.0) ​

Every award can be retrieved as an Open Badges 3.0 / W3C Verifiable Credential, signed with the issuer key above.

GET /certify-badge/award/{guid}/vc
QueryResult
(default) or ?format=jwtThe signed VC-JWT (application/jwt) — import into an OB 3.0 wallet.
?format=jsonThe unsigned OpenBadgeCredential JSON (application/vc+ld+json) — for inspection.
bash
# Signed credential (VC-JWT)
curl https://api.badges.ninja/certify-badge/award/<guid>/vc

# Human-readable credential JSON
curl "https://api.badges.ninja/certify-badge/award/<guid>/vc?format=json"

The credential is a ["VerifiableCredential", "OpenBadgeCredential"] typed VC (contexts https://www.w3.org/ns/credentials/v2 and the OB 3.0 context). Its issuer.id is did:web:api.badges.ninja, and the achievement, recipient identity (hashed email), and issue/expiry dates come from the award.

Verifying a VC-JWT ​

The token is a compact JWS with an EdDSA signature. To verify:

  1. Split the JWT into header.payload.signature.
  2. Read kid from the header — it points into the DID document / JWKS.
  3. Fetch the public key and verify the Ed25519 signature over header.payload.
js
import crypto from "node:crypto";

const [h, p, s] = jwt.split(".");
const jwks = await (await fetch("https://api.badges.ninja/.well-known/jwks.json")).json();
const jwk = jwks.keys[0];
const pub = crypto.createPublicKey({ key: jwk, format: "jwk" });
const ok = crypto.verify(null, Buffer.from(`${h}.${p}`), pub, Buffer.from(s, "base64url"));

Recipients can also grab the credential from the Download menu on their public credential page (Verifiable Credential).

Signature Algorithm ​

Signatures use Ed25519 (EdDSA). The private key is custodied server-side and never exposed; only the public key above is published.

Hosted Verification (Open Badges 2.0) ​

Every credential is also independently verifiable today via its hosted Open Badge 2.0 assertion. See Public Verification for the assertion, badge, and issuer JSON endpoints, and Sharing & Verification for the recipient-facing verification page.

badges.ninja Documentation