Claims and benefits
Published
No, not on its own. We protected a prior-authorization module on five presets and every request got the same answer. Then we renamed the members it reads, and a revoked authorization was accepted, a 140-day-old one was honoured, and in another arm every request in the file was refused - including one whose stated reason was that it had been approved.
What we actually measured
Prior authorization is the payer's main cost control and the member's main obstacle, so it is worth knowing precisely what happens to one under protection. The module we built has the shape these really have: a switch that turns the policy on, a list of services that need an authorization, a staleness limit, an urgency bypass, and a verifier the payer wired in because the authorization records live in their system.
The engine consuming it is a separate installed library, copied in unprotected. Baseline: five presets, twenty-five comparisons, twenty-five identical answers. Protection alone changed nothing about which services proceeded.
The list can be lost from either end, and both ends open the gate
The list of services needing authorization is a rule written as data: three procedure codes, matched against a field on the request. As with any rule of that shape, there are two independent ways to lose it.
Rename the option holding the list and the vendor default is substituted - an empty list, because a library cannot know your policy. Rename the field the codes are matched against and the list survives while matching nothing.
Both produce the same sentence on every request in the file:
PROCEEDS=true not-a-listed-service(...)
A knee replacement, an MRI with no authorization at all, and a revoked authorization all proceed. Every one of them is reported as a service that does not need review, which is a true statement about a list that is now empty or now matches nothing, and a false statement about the policy.
A flag in front of a strict control produces the quiet outcome
The verifier sits behind an enabling switch. We measured each half and the union.
The verifier alone: the library's own permissive default takes over and accepts every authorization presented, including the revoked one:
revoked-authorization-refused PROCEEDS=true authorized(29881 auth AUTH-REVOKED accepted-without-review, ...)
The flag alone: authorization is not enforced at all, and every service proceeds without review.
Both together: behaviourally identical to the flag alone. The flag is checked first, so the strict control behind it is never consulted, and losing it as well costs nothing extra. A pair of names that could each have been noticed produces, together, the quietest outcome available - and in the flag arm the configuration still reports the verifier as caller-supplied and correct. It is present, it is bound, it is right, and it is never called.
We measured this shape in five separate modules this pass and it held in all five, which is the reason it is worth stating as a rule rather than an anecdote: any reasoning of the form 'if this broke we would know' is only valid when the thing that would tell you is not downstream of the thing that broke.
The staleness ceiling failed open
The policy refuses an authorization older than 90 days. We renamed the limit, then the age field on the request, separately.
Both let a 140-day-old authorization through:
mri-on-a-stale-authorization PROCEEDS=true authorized(70553 auth AUTH-1180 reviewed-and-approved-for-m-902, ...)
It reads like a clean approval, because it is one - the record it is approving is simply months out of date. This is a ceiling whose true branch refuses, so skipping it accepts.
The permission flag failed closed, loudly, and said the opposite
The payer's verifier hands back a permission called approved. Rename it and the library reads undefined, treats the missing permission as a denial, and prints the verifier's own reason for approving:
knee-replacement-properly-authorized PROCEEDS=false authorization-refused(reviewed-and-approved-for-m-900)
Refused, because it was approved. Every legitimately authorized service in the file was blocked this way. It is a bad day for scheduling and a good day for safety: somebody calls within the hour and the release is pulled.
The direction here is not luck. A permission that goes missing is falsy, so the answer is no. Had the same field been phrased as a prohibition - denied rather than approved - the identical rename would have let everything through in silence. That phrasing choice costs nothing at design time and decides which way this fails.
Three arms failed safe, and we are reporting them as such
The urgency bypass lets an urgent request proceed without an authorization. Renaming either the option enabling it or the field marking the request urgent had the same effect: the bypass stopped applying and the urgent request was refused.
That is the safe direction. It is not costless - an urgent case waiting on paperwork is a real harm - but nothing is authorized that should not have been. Renaming the authorization number itself also failed safe: every request was refused for presenting no authorization. And renaming the member the authorization is issued to refused every request too, with an accurate reason:
authorization-refused(issued-to-m-900-not-undefined)
A pass that only reports silent disasters is confirming a prior belief rather than measuring. Roughly half the arms in this module fail toward refusal, and that half is genuinely fine.
What actually protects you
Phrase the flag your verifier hands back as a permission, never as a prohibition. This module demonstrates both directions with the same mechanism, and the permission is the one that fails safe. That generalises well beyond obfuscation: a version bump, a serialisation hop that drops undefined keys, a partial response and a hand-written mock all produce the same undefined field.
Do not put a strict control behind a flag that can be lost the same way the control can. If the switch and the switched are both properties of one object in one file, one pattern reaches both, and the quiet half wins.
Prefer allowlists to denylists for the services list. A list of what needs review fails open when it stops matching; a list of what may proceed without review fails closed. That is a design choice available at no cost while you are writing it and at considerable cost afterwards.
Frequently asked questions
Does protecting a prior-authorization module change which services proceed?
Not in what we measured. Five presets covering the ES5 and modern targets plus the string transforms, every request through every build: twenty-five comparisons, twenty-five identical answers.
What happened when the list of services needing review was lost?
Every request proceeded, reported as a service that does not need review. That happened two independent ways - renaming the option holding the list, which substitutes the vendor's empty default, and renaming the field the codes are matched against, which leaves the list intact and matching nothing.
Why did losing two names together produce a quieter result than losing one?
Because the enabling flag is checked before the strict control it guards. Losing the flag means the verifier is never consulted, so losing the verifier too costs nothing extra. The union behaved identically to the flag alone, in five separate modules we measured this pass.
What does a refusal whose reason says it was approved mean?
That a field on the verifier's return shape has moved. We saw a properly authorized knee replacement refused with the stated reason that it was reviewed and approved. It is the clearest triage signature in this series.
Which way does a missing verifier flag fail?
It depends entirely on how the flag is phrased. A permission that goes missing is falsy, so the answer is no and the request is refused - loudly and safely. A prohibition that goes missing permits. Same rename, same undefined value, opposite outcomes.
Did anything fail in a safe direction?
Yes, and it is worth saying so. Roughly half the arms in this module failed toward refusal: the urgency bypass stopped applying, a missing authorization number refused the request, and a missing member binding refused it with an accurate reason. Those are costly but not dangerous.
What is the cheapest safeguard to add?
Write the services list as an allowlist of what may proceed without review, rather than a denylist of what needs it. A denylist that stops matching opens the gate; an allowlist that stops matching closes it, and somebody reports that the same day.
Related reading