EHR Authentication

Purpose

This design explains how Link authenticates to EHR vendor APIs when acquiring data from facility systems.

The scope of this design is EHR authentication for data acquisition. It does not describe Link user login, Admin UI authentication, service-to-service authentication within Link, or authorization policies for Link users.

For EHR vendors that expose FHIR APIs, Link authenticates as an application registered in the vendor's system. The application registration represents the Link integration for that vendor environment. Link uses that registration to request access tokens before making data acquisition requests.

Scope

This design covers:

  • How Link obtains OAuth2 access tokens from EHR vendors.
  • How Link uses JWT client assertions for EHR token requests.
  • How Link signs JWTs using private keys stored in Key Vault.
  • How EHRs validate Link's signed JWTs using public keys.
  • How Link will support vendor-specific key/certificate pairs.
  • How the key association model should remain flexible for future tenant/facility-level overrides.

This design does not cover:

  • Link Admin UI user authentication.
  • Link BFF session management.
  • Link internal service authentication.
  • General user authorization or role-based access control.

OAuth2 JWT Client Assertion Pattern

All supported EHR vendors so far use a form of OAuth2-based authentication. The exact vendor requirements vary, but the high-level workflow is consistent:

  1. Link generates a JWT client assertion using the configured client ID.
  2. Link signs the JWT using a private key.
  3. Link sends the signed JWT to the vendor's authorization endpoint.
  4. The EHR validates the JWT signature and returns an access token.
  5. Link sends the access token as an Authorization: Bearer <token> header on each EHR data acquisition request.

The client ID represents the Link app registration in the vendor's system. The private key is held by Link and used only for signing JWT client assertions. The corresponding public key is made available to the EHR so the EHR can verify that the JWT was signed by Link.

Public Key Distribution

Current Manual Public Key Registration

Historically, Link has provided the public key as part of each facility's request to access the Link app registration.

In practice, this means the public key associated with each facility using the app is copied into the vendor's app registration or access request process. This approach works, but it creates a manual onboarding step for each facility and makes key rotation more operationally difficult.

JWKS-Based Public Key Discovery

Vendors are moving toward validating JWT signatures through a JWKS document.

With this approach, Link publishes public keys at a public JWKS endpoint. The EHR retrieves the JWKS document and uses the matching public key to validate JWT client assertions signed by Link.

This reduces manual public key copy/paste during facility onboarding and creates a cleaner path for key rotation.

In the JWKS-based approach:

  1. Link maintains one or more private signing keys.
  2. Link publishes the corresponding public keys through a JWKS endpoint.
  3. Link includes a kid header in the signed JWT so the EHR can identify which public key should be used for verification.
  4. The EHR retrieves the JWKS document from Link.
  5. The EHR validates the JWT signature using the public key associated with the JWT's kid.
  6. If validation succeeds, the EHR returns an access token.
  7. Link uses the access token for FHIR API requests during data acquisition.

JWKS-Based Authentication Flow

sequenceDiagram
    participant Lnk as "Link Data Acquisition"
    participant VC as "Vendor Configuration"
    participant KV as "Key Vault"
    participant JWKS as "Link JWKS Endpoint"
    participant Auth as "EHR Authorization Server"
    participant API as "EHR FHIR API"

    Lnk-->>VC: Resolve facility EHR vendor and configured key/kid
    VC-->>Lnk: Return vendor auth settings and key/kid reference
    Lnk->>KV: Request signing key or signing operation
    KV-->>Lnk: Return signing capability or private key material
    Lnk->>Lnk: Create JWT client assertion with client_id
    Lnk->>Lnk: Sign JWT and include kid in JWT header
    Lnk->>Auth: POST token request with signed JWT
    Auth->>JWKS: GET Link JWKS document
    JWKS-->>Auth: Return public keys
    Auth->>Auth: Select key by kid and validate JWT signature
    Auth-->>Lnk: Return OAuth2 access token
    Lnk->>API: Request FHIR data with "Authorization: Bearer token"
    API-->>Lnk: Return FHIR response

Key Storage

JWT signing keys are stored in Key Vault. Link does not store private signing key material directly in tenant, facility, vendor, or data acquisition configuration records.

When Link needs to generate a signed JWT, it resolves the applicable key identifier from configuration and requests the key from Key Vault.

The implementation may either retrieve private key material for in-process signing or use a Key Vault-backed signing capability, depending on the deployment and SDK support.

The JWKS endpoint exposes only public key material needed by EHRs to validate signatures. Private keys must never be exposed through the JWKS endpoint, admin UI screens, configuration APIs, logs, or exported architecture documentation.

Vendor-Specific Key Strategy

Link will maintain a separate key/certificate pair per EHR vendor.

Examples:

Vendor Signing Key Strategy
Epic Epic-specific key/certificate pair
Cerner Cerner-specific key/certificate pair
Oracle Oracle-specific key/certificate pair

A single shared key would technically be sufficient for multiple vendors when the same algorithm is supported. However, vendor-specific keys reduce the blast radius if a private key is compromised. If one vendor-specific key is breached, only facilities using that vendor's key are impacted.

Vendor-specific keys are also required when vendors have different signing algorithm requirements. Oracle requires a different algorithm than Epic and Cerner, so Oracle must have its own key regardless of the preferred blast-radius reduction strategy.

Vendor Key Association

Link has a concept of Vendor and supports vendor-level configuration through the vendor configuration screen.

The current plan is to associate each vendor with a specific Key Vault key and kid.

For example:

Vendor Configuration
Epic Key Vault key reference and kid used for Epic JWT client assertions
Cerner Key Vault key reference and kid used for Cerner JWT client assertions
Oracle Key Vault key reference, kid, and algorithm required for Oracle JWT client assertions

At runtime, Link should resolve the signing key from the vendor associated with the facility's EHR configuration. This keeps key management centralized at the vendor level and avoids requiring every facility to independently configure key material when the vendor-level key is sufficient.

Runtime Key Resolution

At runtime, Link resolves the signing key based on the facility's configured EHR vendor.

The initial resolution model is:

  1. Determine the facility's EHR vendor from data acquisition configuration.
  2. Retrieve the vendor-level authentication configuration.
  3. Resolve the Key Vault key reference and kid associated with that vendor.
  4. Use that key/kid when creating and signing the JWT client assertion.
  5. Include the kid in the JWT header so the EHR can select the matching public key from Link's JWKS document.

The configuration model should allow a future facility-level override without requiring a major redesign.

A future resolution order may be:

  1. Use a facility-specific key/kid override, when configured.
  2. Otherwise, use the vendor-level key/kid.

Future Facility-Level Key Overrides

The initial implementation should associate keys at the vendor level. However, the design should remain flexible enough to support tenant/facility-level key overrides in the future.

A facility-level override may be needed if vendor-level keying is not sufficient for a specific facility. For example, a facility may have a policy requiring a unique key/certificate pair for that facility's app registration or authorization workflow.

Tenant/facility-level overrides are not part of the initial implementation, but the configuration model should avoid assumptions that would make this difficult to add later.

Operational Considerations

Key Rotation

Key rotation should be supported without disrupting active facilities.

A typical rotation process is:

  1. Generate a new vendor-specific key/certificate pair in Key Vault.
  2. Publish the new public key in the Link JWKS document.
  3. Update the vendor configuration to reference the new Key Vault key and kid.
  4. Begin signing new JWT client assertions with the new private key and kid.
  5. Allow EHR systems to validate the new key through the JWKS endpoint.
  6. Retire the old key after all affected vendor integrations have moved to the new key.

If tenant/facility-level key overrides are introduced later, the same rotation model should apply to those overrides.

Key Identification

Each public key in the JWKS document must include a stable kid.

The JWT signed by Link must include the same kid in its header so the EHR can select the correct public key.

Vendor configuration should persist the Key Vault key reference and the kid that should be used for JWT signing. The kid used in signed JWTs must align with the corresponding public key published in the JWKS document.

Private Key Protection

Private keys must remain secret and must not be exposed through configuration APIs, logs, JWKS documents, admin UI screens, or exported architecture documentation.

The JWKS endpoint exposes only public key material.

Facility Onboarding

When a vendor supports JWKS validation, facility onboarding should reference the Link-hosted JWKS endpoint instead of requiring public key material to be manually copied into each facility's app registration request.

When a vendor or facility still requires manual public key registration, Link may continue supporting that workflow as a vendor-specific onboarding requirement.

Token Caching

Token responses may be cached according to the vendor-provided expiration period to avoid requesting a new token for every FHIR request.

Token caching should be scoped in a way that avoids cross-facility or cross-vendor token reuse. At minimum, the cache key should account for the facility, vendor, token endpoint, client ID, requested scopes/audience, and any other vendor-specific token request parameters that influence the issued token.

Data Acquisition Integration

EHR authentication is used by Link's data acquisition workflow whenever Link needs to query an EHR FHIR endpoint.

Before issuing FHIR requests, Link obtains an access token from the vendor authorization server. Once the token is received, Link attaches it to each outbound EHR API request:

Authorization: Bearer <access-token>

The access token is used only for EHR API requests associated with the relevant facility/vendor authentication context.

Open Questions

The following implementation details should be confirmed as the design is implemented:

  1. What public URL path will Link expose for the JWKS document?
  2. Will Link retrieve private key material from Key Vault for in-process signing, or will it use a Key Vault-backed signing operation?
  3. What are the exact JWT signing algorithm requirements for Epic, Cerner, and Oracle?
  4. How long do each of the EHR vendors cache JWKS responses, and how should that affect key rotation timing?
  5. Do any facilities require facility-specific keys at launch, or is vendor-level keying sufficient for the initial implementation?

Relationships

flowchart LR
nehr_auth_FAA739A["Design: EHR Authentication"]