Answers the one question the binding form asks about a token an operator is
holding: which of the issuers this tenant may bind to does its
iss name, if any?
🔴 The comparison is not string equality, which is why this operation
exists. A declaration is stored in canonical form — lowercase scheme and
host, default port removed, every trailing slash stripped from the path,
percent-triplets upper-cased — while a token's iss arrives exactly
as its issuer wrote it. Auth0, which carries a first-class preset in the
declaration form, always emits the trailing slash. So a raw comparison reports NO
MATCH for a configuration that is perfectly correct and will authenticate at
runtime, and there is no spelling of the declaration an operator could choose
that would make it agree. This operation runs the SAME selection the operator
probe and authentication run, so a client renders a verdict instead of computing
one.
🔴 It is a POST, and that is deliberate — do not "correct" it
to a GET. The edge and environment NGINX both log
"$request", which is the full request line including the query
string. An iss in a query parameter — or in a path segment,
which is the same thing doubly encoded — would therefore become a durable
tenant-to-issuer correlation in an access log whose retention this surface does
not control. The identifier travels in a body so that it is written nowhere.
Reverting to a GET silently reintroduces that exposure.
🔴 It carries the READ scope, not a write one. The method is
POST for the logging reason above; the operation persists nothing,
emits no audit event, spends no outbound-fetch allowance and is safe to retry.
Attaching a write scope because the verb looks like one would widen authorization
for a read.
No match is a 200 with matched: null — never
a 404 and never a 204. A distinct status would be a
third meaning of 404 on this controller, alongside the tenant-boundary 404, and a
caller could then tell them apart and learn what the uniform refusal withholds. A
blank, malformed or inadmissible iss is likewise a
200/null rather than a 400: it names no declaration,
which is an answer, and an exception escaping a lookup would turn a refusal into
a fault. The one 400 this operation can answer is TRANSPORT — a body
it cannot read, or one carrying a field it does not declare — which says the
request was not one this operation accepts and says nothing about the tenant.
🔴 The maxLength the request schema publishes is
DOCUMENTARY, not a second refusal. It names the bound
canonicalizeIssuerUrl applies before it parses anything; an
oversized iss is still answered 200 with
matched: null, exactly like every other value nothing declares. A
generated client or schema-validating gateway that refused an oversized value
LOCALLY would author on the client side the very second refusal shape this
operation deliberately does not have — so read it as the rule's own bound,
published for a reader, never as a precondition to enforce.
It resolves over the bindable set — the same rows
../bindable-issuers lists, with no enabled filter, so a
declared-but-not-yet-enabled issuer matches. That is the state an operator is
actually in while binding. A matched row is identical to the row that list
publishes for it, including the withheld displayName on an inherited
declaration, so this reveals strictly less than the read beside it.
Ungated. Reading which issuer a token names is not the act that grants
a workload access, and the refusal it will meet at submit is the one that states
the real reason.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||