Standards

Nothing here is invented. Every format is an open specification, and each one is listed so an auditor can check the claim against the credential.

The credential

valid.ca issues Open Badges 3.0 credentials. That format is a W3C Verifiable Credential 2.0 document with an Open Badges context, so a credential satisfies both specifications at once.

Piece Specification
Credential model W3C Verifiable Credentials Data Model 2.0
Achievement format Open Badges 3.0 (1EdTech)
Proof W3C Data Integrity, cryptosuite eddsa-rdfc-2022 (Ed25519 over RDF canonicalization)
Revocation W3C Bitstring Status List, and the same list as an IETF Token Status List for SD-JWTs
Issuer identity did:web, on the issuer's own domain
Second format for wallets SD-JWT VC, media type dc+sd-jwt, with type metadata at its vct URL in English and French
Wallet delivery OpenID for Verifiable Credential Issuance 1.0, pre-authorized code with a six-digit code
Holder binding SD-JWT key binding: a cnf key in the credential, and a key binding JWT per presentation
Wallet presentation OpenID for Verifiable Presentations 1.0, with a DCQL query and a signed request object

The contexts a credential references are bundled with the signing service rather than fetched at signing time. A signature does not depend on a remote URL being up, and a context cannot change underneath an already-signed credential.

Who signs what

Each issuer signs with their own key, under their own did:web. A credential's issuer.id is the training provider, and its proof verifies against a key in the DID document served from that provider's domain.

did:web:valid.ca signs two things: the trust registry at /.well-known/valid-issuers.json, and the request a worker's wallet reads when someone scans it on valid.ca, so the wallet can show who is asking. It never signs a training credential.

valid.ca generates and holds issuer keys, and that arrangement is disclosed in each DID document as a CredentialIssuanceOperator service entry. How issuing works covers what that does and does not mean for the credential.

Revocation

Each issuer has one Bitstring Status List with room for 131,072 credentials. A credential's credentialStatus names the list and the index of its own bit.

The list is a signed Verifiable Credential in its own right, served from the issuer's domain. A verifier reads the whole list to check one credential, so neither valid.ca nor the issuer learns which credential was being checked.

An SD-JWT's status claim points at the same URL, as the IETF Token Status List specifies. Asked for application/statuslist+jwt, that URL answers with the same bits as a Status List Token: a JWT of type statuslist+jwt signed by the issuer, whose sub is the URL. Any other request gets the W3C list. Revoking a credential updates both at once.

Selective disclosure

Alongside the JSON-LD credential, a worker's wallet can collect the same record as an SD-JWT VC with type https://valid.ca/vct/safety-training. That URL serves the type's metadata, so a wallet can label the card and each claim in English or French. The course name, the issuer's name, the award date, and the expiry are public claims. The holder's name and email, the certificate number, and the link to the credential page are disclosures the holder chooses to release, so a worker can prove they hold a current ticket without handing over their email address.

Holder binding

The SD-JWT is bound to a key on the worker's phone. The wallet proves it holds the key when it collects the credential, and the key goes into the credential's cnf claim. To present it, the wallet signs a key binding JWT over the verifier's one-time nonce, the verifier's identifier, and exactly the disclosures it is sending. A copy of the SD-JWT, from a screenshot, a log, or someone else's phone, cannot produce that signature, so it does not verify.

Binding proves the phone, not the person. Whoever checks a worker in person still compares the name the wallet shows with the worker in front of them.

The Open Badge is not bound. It is the copy a worker shares as a file or a link, and anyone holding it can check it.

Identifiers

A credential's id is its page on valid.ca, https://valid.ca/c/{uuid}, which is the URL an issuer prints on a certificate.

The holder appears as an IdentifierEntry holding the SHA-256 hash of their lowercased email address. A verifier who already knows the address can confirm the match; one who does not learns nothing from the credential.

Achievements have stable identifiers of the form https://valid.ca/achievements/{issuer-slug}/{achievement-slug}. They name the achievement inside the credential and are not served as pages.

Conformance

The implementation follows these specifications and has not yet been through formal certification. 1EdTech Open Badges conformance and OpenID conformance submissions are planned, and neither is done. Anything on this page can be checked directly against a credential today, which is the stronger claim of the two.

Wallet delivery has one known gap against OpenID4VCI 1.0: pre-authorized codes do not expire, because there is no resend yet. A worker who moves to a new phone cannot yet collect their SD-JWT again; the Open Badge and the credential page still work.