Skip to main content

Lyrebird OpenAPI - Secure Launch v2

Secure Launch V2: Asymmetric Encryption

Updated this week

Secure Launch V2 is the recommended method for EMR systems to securely launch into Lyrebird with encrypted patient context. It uses asymmetric encryption (ECIES with ECDH) instead of shared secrets, providing stronger security guarantees.

Secure Launch allows EMR systems to pass patient context (name, gender, MRN, etc.) to Lyrebird when launching the application. This context is encrypted to protect sensitive patient data in transit.

The following content is technical specification for the implementation, and guide on how to configure it yourself.

| Feature | V1 (Symmetric) | V2 (Asymmetric) |

|------------โ€“-โ€“----|----------------|-----------------|

| Algorithm | AES-256-CBC | ECIES (ECDH P-256 + AES-256-GCM) |

| Key Type | Shared secret | Public/private keypair |

| Key Distribution | Both parties share secret | Only public key is shared |

| Replay Protection | None | 5-minute timestamp window |

| Integrity Check | None | AES-GCM authentication tag |

| Credential Type | `encryption` | `asymmetric_encryption` |

| Recommended | Legacy only | **Yes** |

Key Parts

1. ECDH (Elliptic Curve Diffie-Hellman): Key agreement protocol using P-256 curve

2. ECIES (Elliptic Curve Integrated Encryption Scheme): Hybrid encryption combining ECDH with AES-GCM

3. AES-256-GCM: Symmetric encryption with authentication for the actual data

Architecture

Encryption Flow (EMR Side)

1. Receive Lyrebird's public key (P-256 EC key in JWK format)

2. Generate an ephemeral keypair for this single encryption

3. Derive shared AES-256 key using ECDH (ephemeral private + Lyrebird public)

4. Construct payload with timestamp and patient data

5. Encrypt using AES-256-GCM with random 12-byte IV

6. Send structured JSON containing all components

Decryption Flow (Lyrebird Side)

1. Parse the encrypted payload (JSON with version, ciphertext, etc.)

2. Import ephemeral public key from payload

3. Derive shared AES-256 key using ECDH (Lyrebird private + ephemeral public)

4. Decrypt using AES-256-GCM

5. Validate timestamp (must be within 5-minute window)

6. Extract patient data from decrypted payload

Encrypted Payload Structure

{

"version": "1.1",

"ephemeralPublicKey": "<base64-encoded JWK>",

"ciphertext": "<base64-encoded encrypted data>",

"iv": "<base64-encoded 12-byte initialization vector>",

"authTag": "<base64-encoded 16-byte authentication tag>"

}

Decrypted Payload Structure

{

"timestamp": 1699900000000,

"patientData": {

"PAT_FIRST_NAME": "John",

"PAT_LAST_NAME": "Smith",

"PAT_GENDER": "M",

"PAT_MRN": "MRN001234",

"PAT_VISIT_ID": "ENC789456",

"USER": "C12345"

}

}

Setup Guide

Configure Secure Launch V2 (Lyrebird Side)

Navigate to `/organisation/api` and configure Secure Launch V2.

Then click โ€œsetupโ€

Share Public Key with EMR

The public key is returned as a Base64-encoded JWK:

{

"kty": "EC",

"crv": "P-256",

"x": "<base64url-encoded x coordinate>",

"y": "<base64url-encoded y coordinate>",

"ext": true,

"key_ops": []

}

EMR Implementation

async function encryptPatientData(patientData, lyrebirdPublicKeyJWK) {

// 1. Generate ephemeral keypair

const ephemeralKeyPair = await crypto.subtle.generateKey(

{ name: "ECDH", namedCurve: "P-256" },

true,

["deriveKey"]

);

// 2. Import Lyrebird's public key

const lyrebirdPublicKey = await crypto.subtle.importKey(

"jwk",

lyrebirdPublicKeyJWK,

{ name: "ECDH", namedCurve: "P-256" },

false,

[]

);

// 3. Derive shared AES key

const sharedKey = await crypto.subtle.deriveKey(

{ name: "ECDH", public: lyrebirdPublicKey },

ephemeralKeyPair.privateKey,

{ name: "AES-GCM", length: 256 },

false,

["encrypt"]

);

// 4. Create payload with timestamp

const payload = JSON.stringify({

timestamp: Date.now(),

patientData: patientData

});

// 5. Generate random IV

const iv = crypto.getRandomValues(new Uint8Array(12));

// 6. Encrypt with AES-GCM

const encrypted = await crypto.subtle.encrypt(

{ name: "AES-GCM", iv: iv, tagLength: 128 },

sharedKey,

new TextEncoder().encode(payload)

);

// 7. Split ciphertext and auth tag

const encryptedArray = new Uint8Array(encrypted);

const ciphertext = encryptedArray.slice(0, -16);

const authTag = encryptedArray.slice(-16);

// 8. Export ephemeral public key

const ephemeralPublicJWK = await crypto.subtle.exportKey(

"jwk",

ephemeralKeyPair.publicKey

);

// 9. Return structured payload

return {

version: "1.1",

ephemeralPublicKey: btoa(JSON.stringify(ephemeralPublicJWK)),

ciphertext: btoa(String.fromCharCode(...ciphertext)),

iv: btoa(String.fromCharCode(...iv)),

authTag: btoa(String.fromCharCode(...authTag))

};

}

Launch URL

Patient Data Fields

| Field | Description | Example |

|------------------|------------------------|-------------|

| `PAT_FIRST_NAME` | Patient first name | `John` |

| `PAT_LAST_NAME` | Patient last name | `Smith` |

| `PAT_GENDER` | Gender code (M/F/U/O) | `M` |

| `PAT_MRN` | Medical Record Number | `MRN001234` |

| `PAT_ACCT` | Patient account number | `ACC123456` |

| `USER` | Clinician identifier | `C12345` |

Extra Fields (optional)

| Field | Description | Example |

|----------------|--------------------------|------------------|

| `PAT_DOB` | Date of birth (YYYYMMDD) | `19850615` |

| `PAT_VISIT_ID` | Encounter/Visit ID | `ENC789456` |

| `PAT_ADDRESS` | Patient address | `123 Main St` |

| `PAT_PHONE` | Patient phone | `0412345678` |

| `PAT_CLASS` | Patient class | `O` (Outpatient) |

| `PAT_LOCATION` | Patient location | `CLINIC-A` |

| `PAT_NHS_NUM` | NHS Number (UK) | `1234567890` |

| `USER_FNAME` | Clinician first name | `Sarah` |

| `USER_LNAME` | Clinician last name | `Jones` |

| `USER_NAME` | Clinician full name | `Dr. Sarah Jones` |

| `USER_EMAIL` | Clinician email | `[email protected]` |

Timestamp Validation

- Payloads include a Unix timestamp (milliseconds)

- Lyrebird validates the timestamp is within a **5-minute window**

- Prevents replay attacks where old URLs are reused

- Future timestamps are rejected (prevents clock skew attacks)

Authentication Tag

- AES-GCM provides authenticated encryption

- 128-bit authentication tag verifies data integrity

- Detects any tampering with the ciphertext

Ephemeral Keys

- Each encryption uses a new ephemeral keypair

- Compromising one payload doesn't affect others

- Provides forward secrecy

No Shared Secrets

- Only the public key is shared with EMR systems

- Private key never leaves Lyrebird's secure storage

- Key compromise on EMR side doesn't expose past data

Did this answer your question?