Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#38]Improve examples #39

Merged
merged 9 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions NOTE

This file was deleted.

40 changes: 32 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
![Release](https://img.shields.io/github/v/release/openwallet-foundation-labs/sd-jwt-js)
![Stars](https://img.shields.io/github/stars/openwallet-foundation-labs/sd-jwt-js)

# SD-JWT Implementation in JavaScript
# SD-JWT Implementation in JavaScript(TypeScript)

This is the reference implmentation of [IETF SD-JWT specification](https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/) written in Javascript. It aims to provide a production-ready, robust and secure way to handle JWTs with selective disclosure capabilities.
This is the reference implmentation of [IETF SD-JWT specification](https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/) written in Typesript. It aims to provide a production-ready, robust and secure way to handle JWTs with selective disclosure capabilities.

Hopae, a founding member of OpenWallet Foundation, is building wallet module in Javascript and need this project as a core component.
Hopae, a founding member of OpenWallet Foundation, is building wallet module in Typesript and need this project as a core component.

Currently compliant with: **draft-ietf-oauth-selective-disclosure-jwt-06**

Expand Down Expand Up @@ -53,23 +53,47 @@ Ensure you have Node.js installed as a prerequisite.
Here's a basic example of how to use this library:

```jsx
import sdjwt from '@hopae/sd-jwt';
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';

// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
lastname: 'Doe',
ssn: '123-45-6789',
id: '1234',
};

// Issuer Define the disclosure frame to specify which claims can be disclosed
const disclosureFrame: DisclosureFrame<typeof claims> = {
_sd: ['firstname', 'lastname', 'ssn'],
};

// Issue a signed JWT credential with the specified claims and disclosure frame
// Return a Encoded SD JWT. Send the credential to the holder
const credential = await sdjwt.issue(claims, privateKey, disclosureFrame);

const presentationFrame = ['firstname', 'id'];
const presentation = await sdjwt.present(encodedSdjwt, presentationFrame);
// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const valid = await sdjwt.validate(credential, publicKey);

// Holder Define the presentation frame to specify which claims should be presented
// The list of presented claims must be a subset of the disclosed claims
// the presentation frame is determined by the verifier or the protocol that was agreed upon between the holder and the verifier
const presentationFrame = ['firstname', 'ssn'];

// Create a presentation using the issued credential and the presentation frame
// return a Encoded SD JWT. Send the presentation to the verifier
const presentation = await sdjwt.present(credential, presentationFrame);

// Verifier Define the required claims that need to be verified in the presentation
const requiredClaims = ['firstname', 'ssn', 'id'];

const verified = sdjwt.verify(presentation, publicKey, ['firstname', 'id']);
// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await sdjwt.verify(presentation, publicKey, requiredClaims);
```

Check out more details in our [documentation](https://github.com/openwallet-foundation-labs/sd-jwt-js/wiki)
Check out more details in our [documentation](https://github.com/openwallet-foundation-labs/sd-jwt-js/wiki) or [examples](./examples/)

## Dependencies

Expand Down
23 changes: 18 additions & 5 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,26 @@ pnpm run all

### Example lists

- all : Example of issue, present and verify the comprehensive data.
- issue: Example of issue SD JWT
- present: Example of present SD JWT
- verify: Example of verify SD JWT
- validate: Example of validate SD JWT
- basic: Example of basic usage(issue, validate, present, verify) of SD JWT
- all: Example of issue, present and verify the comprehensive data.
- custom: Example of using custom hasher and salt generator for SD JWT
- custom_header: Example of using custom header for SD JWT
- sdjwtobject: Example of using SD JWT Object
- decoy: Example of adding decoy digest in SD JWT
- kb: key binding example in SD JWT

### Variables In Examples

- claims: the user's information
- disclosureFrame: specify which claims should be disclosed
- credential: Issued Encoded SD JWT.
- validated: result of SD JWT validation
- presentationFrame: specify which claims should be presented
- presentation: Presented Encoded SD JWT.
- requiredClaims: specify which claims should be verified
- verified: result of verification
- sdJwtToken: SD JWT Token Object
- SDJwtInstance: SD JWT Instance

## More examples from tests

Expand Down
63 changes: 44 additions & 19 deletions examples/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const createKeyPair = () => {

(async () => {
const { privateKey, publicKey } = createKeyPair();

// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
lastname: 'Doe',
Expand All @@ -23,6 +25,8 @@ export const createKeyPair = () => {
hi: 'bye',
},
};

// Issuer Define the disclosure frame to specify which claims can be disclosed
const disclosureFrame: DisclosureFrame<typeof claims> = {
_sd: ['firstname', 'id', 'data2'],
data: {
Expand All @@ -40,35 +44,56 @@ export const createKeyPair = () => {
_sd: ['hi'],
},
};
const encodedSdjwt = await sdjwt.issue(claims, privateKey, disclosureFrame);
console.log('encodedJwt:', encodedSdjwt);
const validated = await sdjwt.validate(encodedSdjwt, publicKey);

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await sdjwt.issue(claims, privateKey, disclosureFrame);
console.log('encodedJwt:', credential);

// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const validated = await sdjwt.validate(credential, publicKey);
console.log('validated:', validated);

const decoded = sdjwt.decode(encodedSdjwt);
console.log({ keys: await decoded.keys() });
const payloads = await decoded.getClaims();
const keys = await decoded.presentableKeys();
// You can decode the SD JWT to get the payload and the disclosures
const sdJwtToken = sdjwt.decode(credential);

// You can get the keys of the claims from the decoded SD JWT
const keys = await sdJwtToken.keys();
console.log({ keys });

// You can get the claims from the decoded SD JWT
const payloads = await sdJwtToken.getClaims();

// You can get the presentable keys from the decoded SD JWT
const presentableKeys = await sdJwtToken.presentableKeys();

console.log({
payloads: JSON.stringify(payloads, null, 2),
disclosures: JSON.stringify(decoded.disclosures, null, 2),
claim: JSON.stringify(decoded.jwt?.payload, null, 2),
keys,
disclosures: JSON.stringify(sdJwtToken.disclosures, null, 2),
claim: JSON.stringify(sdJwtToken.jwt?.payload, null, 2),
presentableKeys,
});

console.log(
'================================================================',
);

// Holder Define the presentation frame to specify which claims should be presented
// The list of presented claims must be a subset of the disclosed claims
// the presentation frame is determined by the verifier or the protocol that was agreed upon between the holder and the verifier
const presentationFrame = ['firstname', 'id'];
const presentedSDJwt = await sdjwt.present(encodedSdjwt, presentationFrame);
console.log('presentedSDJwt:', presentedSDJwt);

const requiredClaimKeys = ['firstname', 'id', 'data.ssn'];
const verified = await sdjwt.verify(
encodedSdjwt,
publicKey,
requiredClaimKeys,
);

// Create a presentation using the issued credential and the presentation frame
// return a Encoded SD JWT. Holder send the presentation to the verifier
const presentation = await sdjwt.present(credential, presentationFrame);
console.log('presentedSDJwt:', presentation);

// Verifier Define the required claims that need to be verified in the presentation
const requiredClaims = ['firstname', 'id', 'data.ssn'];

// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await sdjwt.verify(credential, publicKey, requiredClaims);
console.log('verified:', verified);
})();
48 changes: 48 additions & 0 deletions examples/basic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import sdjwt, { DisclosureFrame } from '@hopae/sd-jwt';
import Crypto from 'node:crypto';

export const createKeyPair = () => {
const { privateKey, publicKey } = Crypto.generateKeyPairSync('ed25519');
return { privateKey, publicKey };
};

(async () => {
const { privateKey, publicKey } = createKeyPair();
// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
lastname: 'Doe',
ssn: '123-45-6789',
id: '1234',
};

// Issuer Define the disclosure frame to specify which claims can be disclosed
const disclosureFrame: DisclosureFrame<typeof claims> = {
_sd: ['firstname', 'lastname', 'ssn'],
};

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await sdjwt.issue(claims, privateKey, disclosureFrame);

// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const valid = await sdjwt.validate(credential, publicKey);

// Holder Define the presentation frame to specify which claims should be presented
// The list of presented claims must be a subset of the disclosed claims
// the presentation frame is determined by the verifier or the protocol that was agreed upon between the holder and the verifier
const presentationFrame = ['firstname', 'ssn'];

// Create a presentation using the issued credential and the presentation frame
// return a Encoded SD JWT. Holder send the presentation to the verifier
const presentation = await sdjwt.present(credential, presentationFrame);

// Verifier Define the required claims that need to be verified in the presentation
const requiredClaims = ['firstname', 'ssn', 'id'];

// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await sdjwt.verify(presentation, publicKey, requiredClaims);
console.log(verified);
})();
62 changes: 46 additions & 16 deletions examples/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,84 @@ export const createKeyPair = () => {
};

(async () => {
// You can create a custom SDJwt instance with your own hasher and salt generator
const SDJwtInstance = sdjwt.create({ hasher: digest, saltGenerator: salt });

const { privateKey, publicKey } = createKeyPair();

// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
lastname: 'Doe',
ssn: '123-45-6789',
id: '1234',
};

// Issuer Define the disclosure frame to specify which claims can be disclosed
const disclosureFrame: DisclosureFrame<typeof claims> = {
_sd: ['firstname', 'id'],
};
const encodedSdjwt = await SDJwtInstance.issue(

// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await SDJwtInstance.issue(
claims,
privateKey,
disclosureFrame,
);
console.log('encodedJwt:', encodedSdjwt);
const validated = await SDJwtInstance.validate(encodedSdjwt, publicKey);
console.log('encodedJwt:', credential);

// Holder Receive the credential from the issuer and validate it
// Return a boolean result
const validated = await SDJwtInstance.validate(credential, publicKey);
console.log('validated:', validated);

const decoded = SDJwtInstance.decode(encodedSdjwt);
console.log({ keys: await decoded.keys() });
const payloads = await decoded.getClaims();
const keys = await decoded.presentableKeys();
// You can decode the SD JWT to get the payload and the disclosures
const sdJwtToken = SDJwtInstance.decode(credential);

// You can get the keys of the claims from the decoded SD JWT
const keys = await sdJwtToken.keys();
console.log({ keys });

// You can get the claims from the decoded SD JWT
const payloads = await sdJwtToken.getClaims();

// You can get the presentable keys from the decoded SD JWT
const presentableKeys = await sdJwtToken.presentableKeys();

console.log({
payloads: JSON.stringify(payloads, null, 2),
disclosures: JSON.stringify(decoded.disclosures, null, 2),
claim: JSON.stringify(decoded.jwt?.payload, null, 2),
keys,
disclosures: JSON.stringify(sdJwtToken.disclosures, null, 2),
claim: JSON.stringify(sdJwtToken.jwt?.payload, null, 2),
presentableKeys,
});

console.log(
'================================================================',
);

// Holder Define the presentation frame to specify which claims should be presented
// The list of presented claims must be a subset of the disclosed claims
// the presentation frame is determined by the verifier or the protocol that was agreed upon between the holder and the verifier
const presentationFrame = ['firstname', 'id'];
const presentedSDJwt = await SDJwtInstance.present(
encodedSdjwt,

// Create a presentation using the issued credential and the presentation frame
// return a Encoded SD JWT. Holder send the presentation to the verifier
const presentation = await SDJwtInstance.present(
credential,
presentationFrame,
);
console.log('presentedSDJwt:', presentedSDJwt);
console.log('presentedSDJwt:', presentation);

// Verifier Define the required claims that need to be verified in the presentation
const requiredClaims = ['firstname', 'id'];

const requiredClaimKeys = ['firstname', 'id'];
// Verify the presentation using the public key and the required claims
// return a boolean result
const verified = await SDJwtInstance.verify(
encodedSdjwt,
presentation,
publicKey,
requiredClaimKeys,
requiredClaims,
);
console.log('verified:', verified);
})();
17 changes: 12 additions & 5 deletions examples/custom_header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,27 @@ export const createKeyPair = () => {

(async () => {
const { privateKey, publicKey } = createKeyPair();
// Issuer Define the claims object with the user's information
const claims = {
firstname: 'John',
lastname: 'Doe',
ssn: '123-45-6789',
id: '1234',
};

// Issuer Define the disclosure frame to specify which claims can be disclosed
const disclosureFrame: DisclosureFrame<typeof claims> = {
_sd: ['firstname', 'id'],
};

const encodedSdjwt = await sdjwt.issue(claims, privateKey, disclosureFrame, {
header: { typ: 'vc+sd-jwt', custom: 'data' },
// Issue a signed JWT credential with the specified claims and disclosures
// Return a Encoded SD JWT. Issuer send the credential to the holder
const credential = await sdjwt.issue(claims, privateKey, disclosureFrame, {
header: { typ: 'vc+sd-jwt', custom: 'data' }, // You can add custom header data to the SD JWT
});
console.log('encodedSdjwt:', encodedSdjwt);
const sdjwttoken = sdjwt.decode(encodedSdjwt);
console.log(sdjwttoken);
console.log('encodedSdjwt:', credential);

// You can check the custom header data by decoding the SD JWT
const sdJwtToken = sdjwt.decode(credential);
console.log(sdJwtToken);
})();
Loading
Loading