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
https://app.lyrebirdhealth.com/app?encryptedPayload=your url encoded payload here
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
