Skip to content

Latest commit

 

History

History
281 lines (217 loc) · 7.04 KB

File metadata and controls

281 lines (217 loc) · 7.04 KB

Low Level API

It is expected that typical usage will involve passing qr-dataUrls or SMART Health Card (shc) strings to the main verify function and getting decoded and verified results.

The library also contains more granular functions for dealing with individual 'artifacts' - the intermediate strings and objects representing the various tiers of encoding.


This 'low-level' API has four classes of functions:

  • Decode
    Decodes artifacts to their decoded form. decode does not perform any validation beyond what is required to decode the data. So don't assume decoded data is valid.
    decode performs 'chaining' - meaning it recursively decodes resulting artifacts.

  • Encode
    Encodes artifacts to their encoded form. encode does perform validation of the artifacts as it encodes them. Unlike decode, encode does not perform 'chaining'. Encoding an artifact only performs that single step.

  • Validate
    Performs validation on an artifact. validate does not perform any encoding or decoding. It only examines the specified artifact and logs errors/warning for invalid properties.

  • Signature
    Verifies the signature of the JSON Web Signature object. This requires the user to supply a directory or public key set. signature may also create a signature for a JSON Web Token (JWT). This requires the user to supply a private signing key.


These functions have a similar calling signature:

  1. set the artifact on the Context object.
  2. call the function passing the Context object.
  3. examine the Context object for the results.

Note: some of the low-level functions are asynchronous. This is denoted with the await keyword in examples below.


Example : Low Level qr decode and verify

This is essentially what the main verify() function does

import { low, Context } from './src/index.js';

// create a new context
const context = new Context();

// set the qr property to a dataUrl representing the QR code image
context.qr = 'data:image/png;base64,iVBORw0KGgo ...'; // truncated

// decode the QR code to shc, compact-jws, flat-jws, jws, etc... (see Context)
await smart.low.decode.qr(context);

// check the context for decoding errors
if(context.errors) {
    // handle errors
}

// check the signature, we need a public keyset (or directory) 
context.options = {
    keys : [{ ... public JWK ...}];
}
await smart.low.signature.verify(context);

// check for signature errors
if(context.errors) {
    // handle errors
}

// validate the decoded jws object as 'decode' only performs minimal validation
smart.low.validate(context);

// check the context for validation errors
if(context.errors) {
    // handle errors
}

// collect the result ...
const fhir = context.fhirBundle;

Note: see Context object for more information.



low.decode

context.qr = 'data:image/png;base64,iVBORw0KGgo ...';
await smart.low.decode.qr(context);
const result = context.shc;
context.shc = 'shc:/1234556...';
await smart.low.decode.shc(context);
const result = context.compact;
context.compact = 'eyJ6aXAiOiJERUYiLCJhbGciOiJFUzI1NiI ...';
smart.low.decode.jws.compact(context);
const result = context.flat;
context.flat = { header: {...}, payload: {...}, signature: {...} };
smart.low.decode.jws.flat(context);
const result = context.jws;
context.flat.header = 'eyJ6aXAiOiJERUYiLCJhbGciOiJFUzI1NiI ...';
smart.low.decode.jws.header(context);
const result = context.jws.header;
context.flat.payload = '3ZLLbtswEEV_JZhuZb2c2LF2dQr0sSgKNO0 ...';
smart.low.decode.jws.payload(context);
const result = context.jws.payload;
context.flat.signature = 'XuJ0cGQ88PmT5drNtymbZiAA7VB ...';
smart.low.decode.jws.signature(context);
const result = context.jws.signature;

low.validate

context.qr = 'data:image/png;base64,iVBORw0KGgo ...';
await smart.low.validate.qr(context);
const errors = context.errors;
context.shc = 'shc:/1234556...';
smart.low.validate.shc(context);
const errors = context.errors;
context.compact = 'eyJ6aXAiOiJERUYiLCJOiJFUzI1NiI ...';
smart.low.validate.jws.compact(context);
const errors = context.errors;
context.flat = { header: '', payload: '', signature: '' };
smart.low.validate.jws.flat(context);
const errors = context.errors;
context.flat.header = 'eyJ6aXAiOiJERUYiLCJhbGczI1NiI ...';
smart.low.validate.jws.header(context);
const errors = context.errors;
context.flat.payload = '3ZLLbtswEEV_JZhuZb2c2LF2dQr0sSgKNO0 ...';
smart.low.validate.jws.payload(context);
const errors = context.errors;
context.flat.signature = 'XuJ0cGQ88PmT5drNtymbZiAA7VB ...';
smart.low.validate.jws.signature(context);
const errors = context.errors;
context.jws = { header: {...}, payload: {...}, signature: {...} };
smart.low.validate.jws(context);
const errors = context.errors;
context.fhirBundle = {...};
smart.low.validate.fhir(context);
const errors = context.errors;

low.encode

context.shc = 'shc:/1234556...';
await smart.low.encode.shc(context); 
const result = context.qr;
context.compact = 'eyJ6aXAiOiJERUYiLCJhbGciOiJFUzI1NiI ...';
await smart.low.encode.jws.compact(context); 
const result = context.shc;
context.flat = { header: '', payload: '', signature: '' };
smart.low.encode.jws.flat(context);  
const result = context.compact;
context.jws.header = 'eyJ6aXAiOiJERUYiLCJhbGciOiJFUzI1NiI ...';
smart.low.encode.jws.header(context); 
const result = context.flat.header;
context.jws.payload = '3ZLLbtswEEV_JZhuZb2c2LF2dQr0sSgKNO0 ...';
smart.low.encode.jws.payload(context); 
const result = context.flat.payload;
context.jws.signature = 'XuJ0cGQ88PmT5drNtymbZiAA7VB ...';
smart.low.encode.jws.signature(context); 
const result = context.flat.signature;
context.jws = { header: {...}, payload: {...}, signature: {...} };
smart.low.encode.jws(context); 
const result = context.flat; 
context.fhirBundle = {...};
context.options = { iss: '<issuer public key url>' };
smart.low.encode.fhir(context); 
const result = context.jws.payload; 

low.signature

// Signature Verification
const keys: [
    {
        kty: "EC",
        kid: "3Kfdg-XwP-7gXyywtUfUADwBumDOPKMQx-iELL11W9s",
        use: "sig",
        alg: "ES256",
        crv: "P-256",
        x: "11XvRWy1I2S0EyJlyf_bWfw_TQ5CJJNLw78bHXNxcgw",
        y: "eZXwxvO1hvCY0KucrPfKo7yAyMT6Ajc3N7OkAB6VYy8"
    }
];
const context = new Context({keys});
context.shc = 'shc:/1234556...';
await smart.low.decode.shc(context);
await smart.low.signature.verify(context);
// Signature sign
const options = {
    privateKey: { ... private JWK ... },
    iss: '<issuer public key url>' 
};
const context = new Context(options);
context.fhir = { ... fhir data ...};
smart.low.encode.fhir(context);  // creates a new jws.payload
await smart.low.signature.sign(context);
const result = context.jwk; // new jwk with header, payload, and signature

Readme