The companion teardown on this site — “The integration service account that reads every record has no owner and no expiry” — sets out the failure this design answers. A credential provisioned once at go-live, scoped to whatever the interface needed when the interface was a nightly batch, still holding that breadth years later; no named person who could say whether it is still required; no expiry that would force anybody to ask; and nobody who has ever watched it be refused. I am not going to re-argue any of that here. This piece assumes it and takes the question that follows, which is the one an architect in a hospital or a sponsor's clinical systems actually has to answer: what do you build, precisely, when the thing holding the credential cannot be taken down, and when the person reading your decision years from now may be opposing counsel rather than a regulator.

The scope is deliberately narrow. Not a governance programme, not a maturity model — a control plane with four moving parts, written up as the reference implementation this practice keeps under the name @authority/nhi — excerpted here rather than distributed as a package: a registry that defines the unit of record, a mint gate that refuses to sign without one, an observation plane that measures what a credential actually does before anything is narrowed, and a revocation plane whose proof of working is an observed refusal rather than an HTTP status code. The derivation is the point: a reader should finish able to see why each part could not have been otherwise, and where I think it breaks.

Healthcare is the right place to derive it for a reason that has nothing to do with market size. This is the sector where the phrase “provable afterwards” needs the least explaining, because the people who run these systems already live with the idea that a decision has to be defensible years later to somebody who was not in the room. It is also one of the few sectors where a regulator has already done the thing the rest of the industry is still arguing about: fixed a maximum tolerable revocation latency, in binding text, with a number in it.

The two mandates that do not fit together

Start with the contradiction, because it is unusually clean and it forces most of the design on its own.

The ASTP/ONC certification criterion for standardised patient and population services, at 45 CFR 170.315(g)(10)(vi), requires that a certified authorisation server “must be able to revoke and must revoke an authorized application's access at a patient's direction within 1 hour of the request”. One hour. Measured from the request, not from the moment an administrator gets round to acting on it. That is a service-level objective written into a certification criterion, and it is rarer than it should be: most regulatory text in this area says an entity must be able to terminate access, and stops there.

The same criterion, a few paragraphs earlier, requires the opposite property of the same credential. At 170.315(g)(10)(v)(A)(1)(ii) and (iii) the authorisation server must issue a refresh token “valid for a period of no less than three months” to confidential apps and to native apps capable of securing a refresh token, and at (v)(A)(2)(ii) it must reissue one “for a new period of no less than three months” when the token is refreshed. So certified health IT is required by regulation to hold a three-month credential and required by regulation to kill it within an hour of being asked.

Now look at how the standards body handles the same problem for system-to-system access — which is where agents live. HL7's SMART App Launch Implementation Guide v2.0.0, the version incorporated by reference at 45 CFR 170.215(c)(2), takes the opposite route in its Backend Services profile: “Access tokens issued under this profile SHALL be short-lived; the expires_in value SHOULD NOT exceed 300”, and “Refresh tokens SHOULD NOT be issued.” The profile defines no revocation mechanism for backend clients at all. Five minutes of exposure, bought by expiry, with no stop button specified.

Two mandates, one credential One body of rules requires the credential to be long-lived. Another requires it to stop almost immediately. Both are binding on the same sector at the same time. CERTIFIED PATIENT-FACING API 45 CFR 170.315(g)(10) Refresh token “valid for a period of no less than three months” (v)(A)(1)(ii) and (iii) Reissued on refresh “for a new period of no less than three months” (v)(A)(2)(ii) Must revoke at the patient’s direction “within 1 hour of the request” (vi) 90 days of life. 60 minutes to stop. SYSTEM-TO-SYSTEM (BACKEND) ACCESS SMART APP LAUNCH v2.0.0 · BACKEND SERVICES Access tokens “SHALL be short-lived”; the expires_in value “SHOULD NOT exceed 300” Backend Services: Authorization Guide “Refresh tokens SHOULD NOT be issued” to backend clients Backend Services: Authorization Guide No revocation mechanism is defined for backend clients at all absence in the profile, not a prohibition 5 minutes of life. No stop button. WHAT BOTH OF THEM ARE SAYING The regulator fixes a maximum tolerable stop time and leaves the credential long-lived. The standard, having no stop mechanism to offer, buys the same bounded exposure by making the credential very short. In both cases the controlled variable is revocation latency, not revocation.

The strongest version of the counter-argument is the standard's, and it deserves stating at full strength rather than in the weakened form that makes it easy to dismiss. Short lifetimes are better engineering than revocation in almost every respect. There is no list to distribute, no cache to invalidate, no epoch to compact, no failure mode in which a stale bundle either lets a dead credential through or refuses a live one. The whole class of distributed-state bugs simply does not arise. A five-minute token bounds your exposure to five minutes without a single line of revocation machinery, and machinery that exists can be broken, misconfigured, or quietly non-functional for a year. If you can get away with expiry alone, you should.

Two things stop you getting away with it here. The first is that expiry bounds the token, not the arrangement. Under the asymmetric client authentication profile a backend client's durable credential is its registered key, not any token; the five minutes limits how long one particular bearer artefact is useful and says nothing about whether the client can immediately obtain another. The second is that the regulation attaches its duty to the arrangement, not the token — and the arrangement in a hospital is an interface that was commissioned in 2019, is fed by an engine somebody else operates, and cannot be turned off between eight and six because a registration desk depends on it. In that setting “make it expire quickly” is not a design decision available to you. Somebody made it in 2019 and they made it the other way.

So the design target is fixed by the sector rather than chosen by me: a credential that lives for months and can be stopped within an hour, where the hour runs from a human request and the evidence that it stopped is an observation at the resource server rather than a status code from the authorisation server.

What has to be true before anything else

The premise, stated once: an identity without a defined lifecycle owner and a tested revocation path is a liability, not an asset. Both qualifiers carry weight. Without an owner there is nobody to ask whether the thing is still needed, so it is never removed. Without a tested revocation path, the ability to remove it is a belief rather than a capability.

In most sectors the first move in an argument like this is to establish that machine identities are principals at all. Here that work is already done, in the regulation's own words. The Security Rule's Access Control standard at 45 CFR 164.312(a)(1) requires technical policies and procedures that allow access “only to those persons or software programs that have been granted access rights as specified in § 164.308(a)(4)”. A software program is a rights-holding principal in the text, on the same footing as a person, and the rights it holds are the ones granted under the administrative provision governing information access management. The paired implementation specification at 164.312(a)(2)(i), Unique User Identification, requires a covered entity to “[a]ssign a unique name and/or number for identifying and tracking user identity” — and that one is REQUIRED, not addressable. Put the two together and a shared service account used by several automations and an agent is not a hygiene problem to be tidied up in the next cycle. It is a defect at the point of use.

The lifecycle duty is equally explicit and more useful than it first appears. 45 CFR 164.308(a)(3)(ii)(C), Termination Procedures, requires procedures “for terminating access to electronic protected health information when the employment of, or other arrangement with, a workforce member ends.” The load-bearing phrase is “or other arrangement with”. The duty is not confined to employees, and it attaches to the ending of an arrangement — a contract concluding, a vendor being replaced, a study closing out, an interface being decommissioned — rather than to the deletion of a row in a directory. Those two events are frequently years apart, and the gap between them is exactly where the credential in the companion teardown lives.

Revision status matters here and I am flagging it rather than burying it. As of the date on this piece, 164.308(a)(3)(ii)(C) is an ADDRESSABLE implementation specification and the rulemaking that would change that has not been finalised. RIN 0945-AA22, published as an NPRM at 90 FR 898 on 6 January 2025, proposes to remove the required/addressable distinction and to add, among other things, a 24-hour notification duty to certain other regulated entities when a workforce member's access to ePHI or to certain electronic information systems is changed or terminated, a technology asset inventory, a network map showing how ePHI moves through information systems, and restoration of certain systems and data within 72 hours. The Spring 2025 Unified Agenda listed the rule in the Final Rule Stage with final action projected for May 2026; that date has passed unmet, and the current agenda entry moves the rule to long-term actions with final action projected for July 2027. I took that change from law-firm briefings reporting the agenda rather than from the agenda's own table, which did not render for automated retrieval, so treat the July 2027 date as reported rather than confirmed. The difference between a proposal and a final rule is the difference between addressable and mandatory, so check the rule's current status before you rely on that single word.

From the premise and those two provisions the consequences follow in order, and it is worth walking them slowly because most of what comes later is forced rather than chosen.

First: the record has to exist at the moment the credential does. Not soon afterwards. A reconciliation process is a bet that discovery outruns creation, and in an estate where issuance is automated and deprovisioning is a ticket, that is a bet against arithmetic. I will not put a ratio on it. I could not find a published non-human-identity measurement specific to healthcare with a stated counting methodology, and the cross-sector figures in circulation are not measuring the same quantity as one another — at least one widely repeated anchor appears to be an average of survey respondents' estimates rather than an enumeration of credentials. The absence is itself the finding: a sector whose permission consequences are among the most legible anywhere has no published measurement of its own machine-identity population that I could locate.

Second: if the record must exist at issuance, something has to refuse to issue when it does not. The refusal has to be mechanical rather than procedural, because a procedural gate is a review meeting and review meetings are the first thing to go when a go-live slips. Mechanically there is exactly one chokepoint, and it is the signing key. If the only code path that reaches the key requires a committed registration, an incomplete record cannot produce a working credential — not as a matter of policy, but as a matter of what the program is capable of doing.

Third: the record must be total. A partial record is worse than no record, because it produces a number that looks like coverage. The rule is that a record missing any required field is not partial — it is undefined, and undefined fails closed. The value of that move is not moral, it is operational. “Undefined” is actionable in a way “too many” is not. An estate with four thousand machine identities and no field set produces a meeting. An estate with three thousand seven hundred defined records and three hundred undefined ones produces a work queue with three hundred items in it, each with a specific missing field and therefore a specific person to go and ask.

Fourth, and this is the field the other sectors do not need: the record must carry its own retention horizon. Everywhere else the record is a live operational object that can be deleted when the credential is. Here it is evidence, and the clock on the evidence starts when the arrangement ends. That is a field, not a policy, and the next section is about why.

Life sciences has been living with the tested-revocation requirement for so long that it is easy to miss. 21 CFR 11.300(c) requires “[f]ollowing loss management procedures to electronically deauthorize lost, stolen, missing, or otherwise potentially compromised tokens, cards, and other devices that bear or generate identification code or password information”. 11.300(b) requires “that identification code and password issuances are periodically checked, recalled, or revised”. And 11.300(e) requires initial and periodic testing of such devices to ensure they function properly and have not been altered. Deauthorisation, periodic recall, and testing that the mechanism still works: the three components of what this piece calls a tested revocation path, in a regulation in force since 1997. Nobody in life sciences needs persuading that the principle is sound. What they need is for it to apply to a credential held by software rather than a token in a drawer.

The DEA's electronic prescribing rule supplies the last piece, and it supplies it as an asymmetry worth copying deliberately. 21 CFR 1311.125(d) requires an institutional practitioner to revoke a practitioner's signing permission “on the date the occurrence is discovered” for the listed events; (d)(1) requires that access “be terminated immediately upon receiving notification from the individual practitioner” that an authentication factor has been lost, stolen, or compromised; and (d)(2) through (4) add expiry of the DEA registration, termination or revocation or suspension of it, and the practitioner no longer being authorised to use the application. Meanwhile (a) and (c) require two designated individuals to be involved in granting access, one of whom must authenticate with a second person's two-factor credential. Dual control on the way in. A single trigger, acted on immediately, on the way out.

The horizon is the constraint

Every sector claims a long audit horizon. This one can cite it, and the citations do not agree with each other, which is the actual design problem.

The Security Rule fixes its own documentation clock at 45 CFR 164.316(b)(2)(i): required documentation must be retained “for 6 years from the date of its creation or the date when it last was in effect, whichever is later.” The clause that costs money is “whichever is later”. A service account that stays in effect for four years does not start its six-year documentation clock until it is finally retired, which means the defensibility window on a credential decision made in 2026 can run past 2036. The record is not a live object with a six-year tail. It is a live object of unknown length with a six-year tail bolted to the far end of it.

Then 45 CFR 164.528(a)(1) gives an individual the right to an accounting of disclosures made “in the six years prior to the date on which the accounting is requested”, and 164.528(b)(2) requires each entry to carry the date of the disclosure, the name of the entity or person who received the protected health information, a brief description of what was disclosed, and a brief statement of the purpose. Read that against an agent acting under a shared service account and the problem is immediate: the covered entity still owes a per-record answer naming the recipient and the purpose, up to six years later. If the credential could not distinguish which automation was acting, the accounting cannot either. This is the most concrete reason an undefined machine identity is a legal liability rather than a backlog item — it converts a routine individual right into something the entity cannot satisfy at any price.

In life sciences the clocks are different again. 21 CFR 11.10(e) requires “secure, computer-generated, time-stamped audit trails” recording operator entries and actions that create, modify, or delete electronic records, requires that audit trail documentation be retained “for a period at least as long as that required for the subject electronic records”, and requires it to be available for agency review and copying. Paired with 21 CFR 312.62(c), which requires an investigator to retain records for two years following approval of a marketing application, or two years after the investigation is discontinued and FDA is notified, the audit horizon for an agent's actions in a clinical study sits well beyond the service life of the system that produced them. And on the provider side, 42 CFR 482.24(b)(1) requires that medical records be retained “in their original or legally reproduced form for a period of at least 5 years” — a floor, on a different object, running from a different date than the HIPAA documentation clock.

Four different retention rules, four different objects, four different start dates. Anyone who assumes one number governs the estate has already made an error they will not discover for years.

And the reviewer is frequently not a regulator. In healthcare the federal statute that most often puts a hostile reader in the room is the False Claims Act, whose limitations provision at 31 U.S.C. 3731(b) bars an action brought more than six years after the violation, or more than three years after the date material facts “are known or reasonably should have been known by the official of the United States charged with responsibility to act”, “but in no event more than 10 years after the date on which the violation is committed.” Ten years is the outer bound, and it is the number the design has to be built against: an identity record and its audit trail must remain intelligible to someone who is trying to make it mean something bad, a decade after the agent acted, without access to anybody who built the system.

So the record carries a retention horizon: the rule that governs it, cited; the moment the arrangement ended, which is null while it is running; and the computed keep-until date, which cannot be computed until the arrangement ends. That last property is why the field cannot be a policy applied at the storage layer. The storage layer does not know when a vendor contract concluded. The registry does, because somebody had to close the record.

Shadow registration, then progressive narrowing

The reason these credentials keep their excess breadth is not that nobody has heard of least privilege. It is that the credential is load-bearing, nobody knows precisely what it touches, and the cost of guessing wrong is a clinical interface failing at an hour when failing is not permitted. Every scoping exercise that starts by proposing a narrower grant is asking somebody to accept an outage risk in exchange for a governance benefit, and they are right to refuse.

So invert the order. Register first, at full existing breadth, changing nothing. Observe. Narrow only to a measured envelope. The sequence matters more than any individual step, and it is the opposite of how most programmes are run.

Shadow registration means the credential enters the registry with all twelve fields complete while its permissions are left exactly as they are. Nothing is enforced, nothing is narrowed, nothing breaks. What changes is that the credential now has an owner who can be asked, a purpose reference, an expiry that will eventually force a renewal decision, and a revocation binding — none of which alters what it can do today. This is the cheapest possible first move, and it is available immediately, because it requires the consent of nobody who operates the interface.

The observation plane then records every call the credential makes as a tuple: resource type, operation, purpose reference, and compartment — the last being the sector-specific dimension, because in healthcare the relevant question is usually not only which endpoint was touched but whose data was inside it. Those tuples accumulate into a usage envelope. The envelope is the evidence, and it is the only thing that ever authorises a narrowing.

Two gates then govern the path from envelope to enforcement. The first is stability: no new element has entered the envelope for a full observation window. The second is a warn-mode run, in which the proposed scope is evaluated alongside the live grant and every call the proposal would have denied is counted while nothing is actually blocked. Enforcement begins only when that count has been zero across a full business cycle — and in this sector the business cycle is not a week. It is month-end, quarter-end, the annual reporting run, the study close-out, the payer batch that a credential does not touch for twenty-six days and then touches hard on the twenty-seventh. A window that does not span the longest periodic job produces an envelope that is confidently wrong.

Progressive narrowing Narrowing before measurement is an outage with a governance rationale attached. 1 · REGISTER All twelve fields complete. Permissions unchanged. 2 · OBSERVE Window W. Record resource, operation, purpose, compartment. 3 · PROPOSE Scope = envelope plus margin M. Derivation recorded. 4 · WARN Proposal runs beside the live grant. Count would-denies. Block none. 5 · ENFORCE Narrowed grant replaces the old. Fails closed outside. gate: is the envelope stable? No new element for a full window W → continue to PROPOSE. Still arriving → loop back to OBSERVE and extend W. A growing envelope is information: the guess would have been wrong. gate: would-deny count Zero across a full business cycle → ENFORCE. Otherwise → back to PROPOSE. THE GOVERNING RULE The only thing that authorises a narrowing is a measurement. The only thing that authorises enforcement is a warn-mode run that denied nothing. Constructed illustration of the design described in the text. W and M are configuration parameters, not measured values.

The obvious objection is that an attacker present during the observation window gets their behaviour baked into the envelope, and a compromise thereby becomes policy. The objection is correct and there is no purely technical answer to it. The partial answer is that the envelope is a proposal rather than an authority: every element in it must be explicable by one of the tenant's declared purpose classes, and anything in the envelope that no purpose class explains is not noise to be tidied up — it is the highest-value output of the entire exercise. It is precisely the access nobody would have described if you had asked them, which means the observation plane doubles as the only honest inventory of what the credential is really for. The shape the design is built to surface is unremarkable traffic that no declared purpose covers — regular, unalarming, invisible to every threshold you have, and present in the envelope. That is a shape, described from the design, not an incident I have observed.

The data model

What follows is the core of the reference package, written against a generic OAuth authorisation server, a generic directory, and a FHIR-shaped resource server, because that is the most common arrangement in this sector. Nothing in it depends on a particular vendor. The strict typing is load-bearing rather than stylistic: every property is required, so a caller cannot construct a partial record and a future contributor cannot add a field without every call site failing to compile. That is the completeness rule expressed in the one place it cannot be forgotten.

Configuration

@authority/nhi — record, observe, mint, drill

Four modules. The first defines what a credential record is and refuses to let a partial one exist. The second accumulates the usage envelope that authorises a narrowing. The third makes registration a precondition of signing. The fourth is the drill that turns a revocation endpoint into a measured number.

The unit of record as a total type. Note what cannot be represented: an owner that is a free-text string, a revocation binding that has never been proven to work other than as an explicit null the mint path refuses, and a retention horizon without a cited rule.

packages/nhi/src/record.ts
// @authority/nhi — the unit of record.
//
// Every property is required. That is the design decision, not a stylistic accident:
// a total type means no caller can construct a partial record, and no contributor can
// add a field later without every call site failing to compile.

declare const brand: unique symbol;
type Brand<T, B extends string> = T & { readonly [brand]: B };

export type TenantId = Brand<string, "TenantId">;
export type CredentialId = Brand<string, "CredentialId">;
export type PurposeRef = Brand<string, "PurposeRef">;
export type EpochKey = Brand<string, "EpochKey">;
export type UnixSeconds = Brand<number, "UnixSeconds">;

/** The principal is the workload, named uniquely. 45 CFR 164.312(a)(2)(i) is a REQUIRED
 *  implementation specification and it says "unique" — a credential shared between two
 *  deployments cannot satisfy it, so the type does not offer a way to express one. */
export type Principal = {
  readonly workload: string;
  readonly deployment: string;
  readonly softwareVersion: string;
};

/** Owner must resolve, not merely exist. A free-text owner decays into the name of
 *  somebody who left. Re-resolution has its own expiry; past it the record is undefined. */
export type OwnerBinding = {
  readonly directoryPrincipal: string;
  readonly displayName: string;
  readonly resolvedAt: UnixSeconds;
  readonly resolutionExpiresAt: UnixSeconds;
  readonly escalationPrincipal: string;
};

/** RFC 7009 s3 notes that for self-contained access tokens "some (currently
 *  non-standardized) backend interaction between the authorization server and the
 *  resource server may be used when immediate access token revocation is desired".
 *  That interaction is the epoch bundle. provenPropagationSeconds is the drill result;
 *  null means the path has never been shown to work. */
export type RevocationBinding = {
  readonly endpoint: string;
  readonly epochKeys: readonly EpochKey[]; // narrowest first
  readonly lastProvenRefusalAt: UnixSeconds | null;
  readonly provenPropagationSeconds: number | null;
  readonly enforcementPoint: string;
};

/** The clock starts when the arrangement ends, per 45 CFR 164.316(b)(2)(i)
 *  ("whichever is later"), so keepUntil is not computable while the credential lives. */
export type RetentionHorizon = {
  readonly governingRule: string; // cited, e.g. "45 CFR 164.316(b)(2)(i)"
  readonly minimumYears: number;
  readonly arrangementEndedAt: UnixSeconds | null;
  readonly keepUntil: UnixSeconds | null;
};

export type ScopeState =
  | { readonly mode: "shadow"; readonly grant: readonly string[]; readonly observingSince: UnixSeconds }
  | { readonly mode: "warn"; readonly grant: readonly string[]; readonly proposed: readonly string[]; readonly since: UnixSeconds }
  | { readonly mode: "enforced"; readonly grant: readonly string[]; readonly narrowedAt: UnixSeconds; readonly envelopeDigest: string };

export type NhiRecord = {
  readonly tenant: TenantId;
  readonly id: CredentialId;
  readonly issuer: string;
  readonly principal: Principal;
  readonly audience: readonly string[];
  readonly material: { readonly kid: string; readonly jwksUri: string; readonly alg: string };
  readonly purpose: PurposeRef;
  readonly owner: OwnerBinding;
  readonly expiry: UnixSeconds;
  readonly revocation: RevocationBinding;
  readonly retention: RetentionHorizon;
  readonly scope: ScopeState;
};

export type Undefined = { readonly ok: false; readonly missing: readonly string[] };
export type Defined = { readonly ok: true; readonly record: NhiRecord };

const REQUIRED_FIELDS = [
  "tenant", "id", "issuer", "principal", "audience", "material",
  "purpose", "owner", "expiry", "revocation", "retention", "scope",
] as const;

/** The only constructor. A draft that is missing anything is not partial; it is undefined,
 *  and the caller receives the field list rather than a record. "Undefined" is actionable
 *  in a way "too many" is not: each missing field names a person to ask. */
export function defineRecord(draft: Partial<NhiRecord>): Defined | Undefined {
  const missing: string[] = [];
  for (const field of REQUIRED_FIELDS) {
    if (draft[field] === undefined || draft[field] === null) missing.push(field);
  }
  if (draft.audience !== undefined && draft.audience.length === 0) missing.push("audience:empty");
  if (draft.material !== undefined && draft.material.jwksUri.startsWith("https://") === false) {
    // SMART v2.0.0 prefers a TLS-protected JWK Set URL over a static key set precisely
    // because a static registration cannot support rotation.
    missing.push("material:jwksUri-not-tls");
  }
  return missing.length === 0
    ? { ok: true, record: draft as NhiRecord }
    : { ok: false, missing };
}

The signing implementation, the epoch bundle format, and the directory adapter are deliberately absent: they are the parts that differ per estate, and pretending otherwise is how reference implementations become shelfware.

The control path, step by step

Six bands, and the dependency runs upward: no band can be trusted further than the completeness of the one beneath it.

The control path, layer by layer Read from the bottom up. Each band names what it does and the property it must hold; no band can be trusted further than the completeness of the band beneath it. 6 · EVIDENCE LEDGER Which principal acted, on which record, under which purpose reference, against which epoch of the revocation bundle. Must outlive the system that produced it. 5 · REVOCATION PLANE Signed epoch bundle at the enforcement point, so refusal needs no call home. A drill mints a canary, proves acceptance, revokes, polls until refused. Last proven refusal gates minting. Never proven means never issued. 4 · NARROWING CONTROLLER Proposes scope from the observed envelope plus a stated margin, then runs the proposal in warn mode beside the live grant and counts would-denies. Enforcement begins only after a clean business cycle. 3 · OBSERVATION PLANE The credential is registered and runs at its existing breadth while every call is recorded as resource, operation, purpose and compartment. Nothing is narrowed on a guess. 2 · MINT GATE The only code path that reaches the signing key. Registration is a precondition of issuance, not a later reconciliation. An undefined record cannot produce a working credential. 1 · REGISTRY OF RECORD Tenant, id, issuer, principal, audience, material, purpose, owner, expiry, revocation binding, retention horizon, scope state — as a total type. A record missing any field is not partial. It is undefined. EVERY BAND MUST STILL BE EXPLICABLE TO SOMEONE WHO WAS NOT THERE, A DECADE LATER
  1. A credential is requested. The registry attempts to define a record from the draft. If any field is absent the request is refused with the field list, and that list is the work queue — each missing field names a specific person to ask.
  2. The mint gate re-resolves the owner, checks the purpose reference against the tenant's own registry without interpreting it, and checks the revocation binding: never proven, proof stale, or measured propagation above the ceiling are three separate refusals with three different remedies.
  3. On success the credential is signed and a ledger row is written with resolved values rather than identifiers, because that row has to be legible after the registry database is gone.
  4. The credential runs in shadow mode at its existing breadth. The observation plane records each call as resource type, operation, purpose and compartment, and declares which paths it can actually see.
  5. When the envelope has been stable for a full window, the narrowing controller derives a proposal from it, separates out anything no declared purpose explains, and runs the proposal in warn mode beside the live grant.
  6. When the would-deny count has been zero for a full business cycle, the narrowed grant replaces the old one and the credential fails closed outside its envelope.
  7. Independently and on a schedule, the drill mints a canary against the same binding, proves it is accepted, revokes it, and polls the real enforcement point until it is refused. The elapsed time becomes provenPropagationSeconds, and if the canary is still accepted when the budget runs out, that is recorded as the finding it is.
  8. When the arrangement ends, the record is closed rather than deleted: arrangementEndedAt is set, keepUntil is computed from the cited governing rule, and the evidence enters its retention horizon.

The one decision in that path worth defending on its own is the epoch bundle — a signed list, distributed to the enforcement point, that lets a resource server refuse a revoked credential without calling back to the issuer. Introspecting every token on every request is simpler, and I would prefer it if it were available. It is not, for two reasons specific to this setting. The enforcement point is frequently not yours: an interface engine, a vendor-operated FHIR facade, a middleware tier procured in 2018. And a synchronous dependency on the authorisation server puts the availability of a clinical read path behind the availability of a governance component, which is precisely the trade this sector cannot make.

RFC 7009 is unusually candid about why the bundle is necessary rather than merely convenient. Its cascade is advisory: if the token presented is a refresh token, the authorisation server “SHOULD also invalidate all access tokens based on the same authorization grant” — SHOULD, and only where the server supports access-token revocation at all. And its implementation note in Section 3 states that for self-contained access tokens “some (currently non-standardized) backend interaction between the authorization server and the resource server may be used when immediate access token revocation is desired”. That sentence is the whole design space. There is no standard mechanism; you either build the backend interaction, or your true stop-working time is bounded below by the token's remaining lifetime, whatever the revocation endpoint said.

One more thing the sector's own standard already gives you, which is worth taking. SMART v2.0.0's asymmetric client authentication profile defines the credential material precisely enough to be inventoried without inventing anything: the authentication JWT's exp “SHALL be no more than five minutes in the future”; the kid header's “identifier SHALL be unique within the client's JWK Set”; a TLS-protected JWK Set URL is strongly preferred over a static key set, because a static registration cannot support rotation; and servers must check that a jti has not been seen before for that iss within the maximum JWT lifetime. Issuer, principal, key identifier and expiry are all named fields in the standard, so a record missing any of them is undefined by the standard's own terms rather than merely by mine — useful in a room where the field set is being called governance overhead.

Where this design fails

A design piece without an honest failure analysis is marketing. These are the failures I can find in my own, in roughly descending order of concern.

The epoch bundle is a cache, and every cache has a staleness window. Failing closed on a stale bundle converts a distribution outage into a clinical availability incident, and in a setting where the system cannot be taken down that is not a rhetorical trade — it is the reason the control gets switched off after the first bad night. The mitigation is two-tier and it is a choice with a name rather than a solution: a stale bundle refuses all new grants immediately, while sessions already established continue within a bounded grace period, and every decision taken on the grace path is written to the ledger as an exception to be reviewed. That converts an availability failure into an evidence obligation, which is the best trade I know of. It does not make the problem go away.

The one-hour clock does not start where I can measure it. The criterion measures from the patient's request. My drill measures from the revocation call. Between those two points sits a call centre, a portal form, a ticket queue and a human being, and no amount of TypeScript closes that gap. Everything this design produces is therefore a lower bound on the true latency, and it should be published as one. A system that propagates a revocation in ninety seconds and takes four hours to hear about it is not compliant; it is well-instrumented on the wrong half of the problem.

The observation plane will be confidently incomplete. A great deal of healthcare integration is not an HTTP API. Direct database connections, file drops onto a share, HL7 v2 feeds over a tunnel, an SFTP job that has run since before anybody currently employed arrived. The plane sees what it instruments, and an envelope derived from partial visibility is more dangerous than no envelope, because it looks like evidence. Hence the coverage field in the type: a credential whose traffic includes an uninstrumented path is marked not-narrowable rather than narrowed, and the honest output for that credential is a registration and an owner, with the scope left exactly as it was.

Purpose can be made meaningless in an afternoon. The design deliberately refuses to let the platform interpret purpose semantics, because the platform has no business knowing what a tenant's agents are for. The cost of that refusal is that a tenant can declare one purpose class called operations, point everything at it, and satisfy every check in the system while conveying nothing. Nothing in the design prevents this. What the design does give you is that the emptiness is visible and countable: one class covering every credential is a one-line query, and a purpose distribution is the kind of artefact that survives contact with an auditor rather badly, which is the point.

Owner records decay faster than anyone plans for. Re-resolution with its own expiry is the mitigation, and it is a real one, but it introduces a failure I take seriously: undefined-fails-closed applied to a live clinical interface at two in the morning is the single most likely way this entire control gets removed from production. So the rule is asymmetric on purpose, in the same shape the DEA rule uses. An expired owner resolution blocks minting and blocks renewal. It never interrupts a credential that is already working. The consequence is that a credential whose owner has left keeps working until its expiry, which is a real weakness, and I would rather carry it than carry the alternative.

The drill proves the canary, not the credential. A canary refused at one enforcement point proves the path works for credentials of that class, against that enforcement point, with that JWKS cache warm. It proves nothing about a credential with a different audience, a different resource server, or a vendor tier that caches keys on a schedule nobody documented. Drills therefore have to be per-binding rather than per-platform, which multiplies the operational cost by the number of distinct enforcement points in the estate — and in a hospital that number is not small. I have no way to reduce it that does not amount to assuming the thing being tested.

This design does not find the credentials nobody minted. Shadow registration only covers what routes through the plane. The population that predates it — including, precisely, the integration account in the companion teardown — is untouched by everything above. Discovery is a genuinely different problem with different tooling and different failure modes, and I am not going to pretend a mint gate solves it. What the mint gate does is stop the population growing, which changes discovery from a race into a finite piece of work. That is a smaller claim than the one usually made and it is the one I can defend.

Dual control on issuance buys integrity and sells availability. Copying the DEA's asymmetry means a credential cannot be minted by one person acting alone, which is correct on a Tuesday afternoon and expensive at three in the morning during an incident. A break-glass path is therefore mandatory, and the only defensible form of it produces a fully defined record with an expiry measured in hours and a ledger row naming whoever invoked it. A break-glass path that produces an undefined record has reintroduced the entire problem under a more sympathetic name.

What it costs

Some of this I know. Some of it I have not measured, and where I have not I am going to say so rather than supply a number that sounds like one.

Request-path latency: small in principle, unmeasured in practice. Verification is local — a bundle lookup and a signature check the enforcement point is already performing — so the marginal cost on the authorisation path should be a hash-set membership test. I have not measured it inside a production FHIR server and I am not going to assert a figure. The measurement is planned and the design of it is specific: added p99 latency at the enforcement point across a range of bundle sizes, against a control with the bundle check disabled, on the same hardware and the same query mix. Until that runs, treat the latency claim as reasoning rather than evidence.

Distribution cost grows with revocations, not with credentials. The bundle carries revoked identifiers, so its size tracks the revocation rate and the epoch retention window rather than the population. That is the right shape, but it makes epoch compaction a first-class operational concern rather than a later optimisation: without it the bundle grows monotonically, and the estate that runs this longest is the one that discovers the problem. Compaction is in the design; the schedule is an estate-specific parameter I cannot supply.

The operational burden lands in the first month, on the gate. A mint gate creates a failure mode that did not exist before: refusal to issue. Every refusal is a person who cannot ship, and the first month is substantially about the gate rather than about credentials. That is a feature — the refusals are previously invisible work made visible — but budget it as an on-call load and staff it, because the failure mode of not staffing it is a permanent exception list, and a permanent exception list is the control's obituary.

Migration difficulty is legal work, not engineering work. The hardest field to populate is not the owner and it is not the purpose. It is the retention horizon's governing rule, because somebody must decide, per record, which of the four clocks in the previous section applies — or a state requirement I have not read. That is counsel's decision. Engineering can build the field, enforce that it is non-empty, and refuse to mint without it. Engineering cannot fill it in.

There is one more cost, and it is the honest ceiling on everything above: I could not find a published measurement of revocation propagation latency in healthcare. Not a conformance-testing result, not a surveillance finding, not a vendor's own number — nothing giving the mean time from a revocation request to actual enforcement at a resource server, or the rate at which revocation silently fails to take effect. ASTP/ONC mandates one hour in binding text. I located no published evidence that anyone measures themselves against it. The gap between a binding one-hour rule and zero public evidence of achieved latency is not a gap in my research; it is the state of the art, and it is the strongest argument I know for building the drill before building anything else.

Two verification caveats, stated rather than hidden. First, hhs.gov refuses automated retrieval, so the OCR material below was read from HHS-hosted page content rather than from the signed resolution agreement. On that basis: Pagosa Springs Medical Center, a Colorado critical access hospital, paid $111,400 and adopted a corrective action plan after a former employee retained remote access to a web-based scheduling calendar containing ePHI; OCR found impermissible disclosure affecting 557 individuals because the hospital failed to deactivate the former employee's username and password after termination, and separately found no business associate agreement with the calendar vendor. Confirm those figures against the agreement itself before repeating them. Second, the NPRM figures cited earlier come from HHS's own summary rather than the Federal Register preamble, which did not render completely for automated reading.

That action is the closest available precedent for an unrevoked agent identity, and what it establishes is that “the account was still live” is a finding an enforcement body has already made and penalised. Not a hypothetical. A hospital, a credential nobody deactivated, and a settlement.

A note on scope, because the citations above are all United States federal text. That is not a claim about where the problem lives; it is a claim about where I could read the operative text and quote it exactly. The shape of the design is jurisdiction-independent — wherever a duty attaches to the ending of an arrangement rather than the deletion of a record, and wherever an accounting obligation survives the system that produced it, the same twelve fields and the same mint gate follow. India's data protection regime and the Gulf's health-sector supervisory frameworks each impose their own access and retention duties, and I have not read their operative text closely enough for this piece to characterise them, so I am not going to. Someone building this in Riyadh or Bengaluru should expect the field set to survive and the retention horizon's governing rule to change.

What to build first, given one week

Not the platform. One credential, and the smallest loop that produces a number.

  1. Day one: take the credential from the teardown — the integration account with the broadest read — and write its record by hand, all twelve fields. You will not be able to complete it. Which field defeats you is the finding, and it is usually the owner or the revocation binding.
  2. Day two: put the mint gate on exactly one issuance path, for new credentials only. Not the estate, not a migration. One path, refusing to sign without a complete record, with every refusal carrying its field list.
  3. Day three: run the drill against a canary on that path. Publish whatever number comes out, including the outcome where the canary is still accepted when the budget expires. That result is more valuable than a good one, because it is the one nobody has.
  4. Day four: turn on the observation plane for the single credential from day one, with no enforcement and no proposal. Declare its coverage honestly, including the paths it cannot see.
  5. Day five: get counsel to name the governing retention rule for that one record and compute keep-until from the end of the arrangement rather than from creation. One record, one citation. The pattern generalises; the first instance is the expensive one.

Two things not to do in that week, both of which are the instinctive first move. Do not start with discovery across the estate: it produces a large number, the number produces a meeting, and the meeting produces a programme rather than a control. And do not narrow anything — narrowing in week one is a guess with an outage attached, and one outage on a clinical interface costs you the right to be near the problem for a long time afterwards.

The design in this piece is not clever and it is not new. It is the same lifecycle discipline 21 CFR Part 11 has required for tokens in drawers since 1997, applied to credentials held by software, with one addition the older regulation did not need: the evidence has to outlive the system, because the reader will arrive years later and will not be friendly. Everything else — the total type, the mint gate, the shadow registration, the epoch bundle — is machinery for making that discipline hold in an estate that cannot be stopped while you fix it.