Skip to content

Commit cb05564

Browse files
GabeTallTed
andauthored
Add JSON Schema for Verifiable Credentials (#977)
* first draft of schema * tests and readme * pr comments * add proof chain and proof arrays * add vp schema and tests * remove unused dep * update readme * Update schema/verifiable-presentation/verifiable-presentation-schema-test.js Co-authored-by: Ted Thibodeau Jr <[email protected]> * Update schema/README.md Co-authored-by: Ted Thibodeau Jr <[email protected]> * Update schema/README.md Co-authored-by: Ted Thibodeau Jr <[email protected]> Co-authored-by: Ted Thibodeau Jr <[email protected]>
1 parent 6bfde2b commit cb05564

20 files changed

+982
-2
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
**/node_modules
1111
**/.DS_Store
1212
**/.vscode
13-
13+
**/package-lock.json

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,14 @@
1414
"bugs": {
1515
"url": "https://github.com/w3c/vc-data-model/issues"
1616
},
17-
"homepage": "https://github.com/w3c/vc-data-model"
17+
"homepage": "https://github.com/w3c/vc-data-model",
18+
"dependencies": {
19+
"ajv": "^8.11.0",
20+
"assert": "^2.0.0",
21+
"fs": "^0.0.1-security",
22+
"mocha": "^10.1.0"
23+
},
24+
"scripts": {
25+
"test-schema": "mocha 'schema/**/*.js'"
26+
}
1827
}

schema/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Verifiable Credentials JSON Schema
2+
3+
This directory defines [JSON Schemas](https://json-schema.org/) for the Verifiable Credentials Data Model.
4+
5+
Currently, this implementation makes use of **JSON Schema version 2020-12**:
6+
- [JSON Schema Core](https://json-schema.org/draft/2020-12/json-schema-core.html)
7+
- [JSON Schema Validation](https://json-schema.org/draft/2020-12/json-schema-validation.html)
8+
- [Relative JSON Pointers](https://json-schema.org/draft/2020-12/relative-json-pointer.html)
9+
10+
# Schemas
11+
12+
There are two schemas provided, each with associated tests:
13+
14+
- [Verifiable Credential JSON Schema](verifiable-credential/verifiable-credential-schema.json)
15+
- [Verifiable Presentation JSON Schema](verifiable-presentation/verifiable-presentation-schema.json)
16+
17+
# Tests
18+
19+
A limited set of tests against examples in the specification are included. To run these tests, you can use the following command, after `npm i`:
20+
21+
```bash
22+
npm run test-schemas
23+
```
24+
25+
The tests rely on examples featured in the spec. Currently these examples have been copy-pasted, and there is no guarantee they are in sync with the spec. This should be improved!

schema/__fixtures__/ajv.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const Ajv2020 = require("ajv/dist/2020");
2+
const ajv = new Ajv2020({allErrors: true});
3+
module.exports = ajv;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/1872",
7+
"type": ["VerifiableCredential", "AlumniCredential"],
8+
"issuer": "https://example.edu/issuers/565049",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"alumniOf": {
13+
"id": "did:example:c276e12ec21ebfeb1f712ebc6f1",
14+
"name": [{
15+
"value": "Example University",
16+
"lang": "en"
17+
}, {
18+
"value": "Exemple d'Université",
19+
"lang": "fr"
20+
}]
21+
}
22+
},
23+
"proof": {
24+
"type": "RsaSignature2018",
25+
"created": "2017-06-18T21:19:10Z",
26+
"proofPurpose": "assertionMethod",
27+
"verificationMethod": "https://example.edu/issuers/565049#key-1",
28+
"jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5XsITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUcX16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtjPAYuNzVBAh4vGHSrQyHUdBBPM"
29+
}
30+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.gov/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
},
17+
"proof": {
18+
"type": "Ed25519Signature2020",
19+
"created": "2021-11-13T18:19:39Z",
20+
"verificationMethod": "https://example.edu/issuers/14#key-1",
21+
"proofPurpose": "assertionMethod",
22+
"proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz"
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/14",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"expirationDate": "2020-01-01T19:23:24Z",
11+
"credentialSubject": {
12+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
13+
"degree": {
14+
"type": "BachelorDegree",
15+
"name": "Bachelor of Science and Arts"
16+
}
17+
}
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/14",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
},
17+
"credentialStatus": {
18+
"id": "https://example.edu/status/24",
19+
"type": "CredentialStatusList2017"
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/14",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
},
17+
"credentialSchema": {
18+
"id": "https://example.org/examples/degree.json",
19+
"type": "JsonSchemaValidator2018"
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/14",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
},
17+
"refreshService": {
18+
"id": "https://example.edu/refresh/3732",
19+
"type": "ManualRefreshService2018"
20+
}
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/14",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
},
17+
"termsOfUse": [{
18+
"type": "IssuerPolicy",
19+
"id": "http://example.com/policies/credential/4",
20+
"profile": "http://example.com/profiles/credential",
21+
"prohibition": [{
22+
"assigner": "https://example.edu/issuers/14",
23+
"assignee": "AllVerifiers",
24+
"target": "http://example.edu/credentials/3732",
25+
"action": ["Archival"]
26+
}]
27+
}]
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/14",
9+
"issuanceDate": "2010-01-01T19:23:24Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
},
17+
"evidence": [{
18+
"id": "https://example.edu/evidence/f2aeec97-fc0d-42bf-8ca7-0548192d4231",
19+
"type": ["DocumentVerification"],
20+
"verifier": "https://example.edu/issuers/14",
21+
"evidenceDocument": "DriversLicense",
22+
"subjectPresence": "Physical",
23+
"documentPresence": "Physical",
24+
"licenseNumber": "123AB4567"
25+
}]
26+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"@context": [
3+
"https://www.w3.org/2018/credentials/v1",
4+
"https://www.w3.org/2018/credentials/examples/v1"
5+
],
6+
"id": "http://example.edu/credentials/3732",
7+
"type": ["VerifiableCredential", "UniversityDegreeCredential"],
8+
"issuer": "https://example.edu/issuers/565049",
9+
"issuanceDate": "2010-01-01T00:00:00Z",
10+
"credentialSubject": {
11+
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
12+
"degree": {
13+
"type": "BachelorDegree",
14+
"name": "Bachelor of Science and Arts"
15+
}
16+
}
17+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
const fs = require('fs');
2+
const assert = require('assert');
3+
const ajv = require('../__fixtures__/ajv');
4+
5+
const verifiableCredentialSchema = "/verifiable-credential-schema.json";
6+
const schema = JSON.parse(fs.readFileSync(__dirname + verifiableCredentialSchema));
7+
8+
describe('Verifiable Credential', function () {
9+
describe('JSON Schema', function () {
10+
11+
it('should validate example 1 using JSON Schema 2020-12 ', function () {
12+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-1.json'));
13+
const validate = ajv.compile(schema);
14+
const valid = validate(data);
15+
16+
assert.equal(null, validate.errors);
17+
assert.equal(true, valid);
18+
});
19+
20+
it('should validate example 4 using JSON Schema 2020-12 ', function () {
21+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-4.json'));
22+
const validate = ajv.compile(schema);
23+
const valid = validate(data);
24+
25+
assert.equal(null, validate.errors);
26+
assert.equal(true, valid);
27+
});
28+
29+
it('should validate example 11 using JSON Schema 2020-12 ', function () {
30+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-11.json'));
31+
const validate = ajv.compile(schema);
32+
const valid = validate(data);
33+
34+
assert.equal(null, validate.errors);
35+
assert.equal(true, valid);
36+
});
37+
38+
it('should validate example 12 using JSON Schema 2020-12 ', function () {
39+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-12.json'));
40+
const validate = ajv.compile(schema);
41+
const valid = validate(data);
42+
43+
assert.equal(null, validate.errors);
44+
assert.equal(true, valid);
45+
});
46+
47+
it('should validate example 13 using JSON Schema 2020-12 ', function () {
48+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-13.json'));
49+
const validate = ajv.compile(schema);
50+
const valid = validate(data);
51+
52+
assert.equal(null, validate.errors);
53+
assert.equal(true, valid);
54+
});
55+
56+
it('should validate example 18 using JSON Schema 2020-12 ', function () {
57+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-18.json'));
58+
const validate = ajv.compile(schema);
59+
const valid = validate(data);
60+
61+
assert.equal(null, validate.errors);
62+
assert.equal(true, valid);
63+
});
64+
65+
it('should validate example 20 using JSON Schema 2020-12 ', function () {
66+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-20.json'));
67+
const validate = ajv.compile(schema);
68+
const valid = validate(data);
69+
70+
assert.equal(null, validate.errors);
71+
assert.equal(true, valid);
72+
});
73+
74+
it('should validate example 21 using JSON Schema 2020-12 ', function () {
75+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-21.json'));
76+
const validate = ajv.compile(schema);
77+
const valid = validate(data);
78+
79+
assert.equal(null, validate.errors);
80+
assert.equal(true, valid);
81+
});
82+
83+
it('should validate example 23 using JSON Schema 2020-12 ', function () {
84+
const data = JSON.parse(fs.readFileSync(__dirname + '/example-23.json'));
85+
const validate = ajv.compile(schema);
86+
const valid = validate(data);
87+
88+
assert.equal(null, validate.errors);
89+
assert.equal(true, valid);
90+
});
91+
});
92+
});

0 commit comments

Comments
 (0)