Labels and Annotations
AuthProxy attaches Kubernetes-style labels (key=value metadata) and annotations (free-form key=value pairs) to every long-lived resource. Labels are the lightweight integration surface between AuthProxy and your host application: tag a connection with your tenant id, search for it later by selector, and have the same tag appear automatically on every request log entry that connection produces.
This page is the reference for the label system — what labels exist, how they propagate, and how to query them.
Quick start
Section titled “Quick start”Tag a connection with your tenant id and environment:
PATCH /api/v1/connections/cxn_abc123Content-Type: application/json
{ "labels": { "app.example.com/tenant-id": "tenant-42", "app.example.com/env": "production" }}List all connections in production for that tenant:
GET /api/v1/connections?labelSelector=app.example.com/tenant-id=tenant-42,app.example.com/env=productionFind every request log entry produced by that tenant:
GET /api/v1/metrics/request-events?labelSelector=app.example.com/tenant-id=tenant-42You did not have to write a separate “AuthProxy connection id → my tenant id” mapping table. The label travelled with the connection onto every request log entry automatically (see Carry-forward).
Where labels and annotations live
Section titled “Where labels and annotations live”Every namespace-scoped resource carries labels and annotations columns:
| Resource | Notes |
|---|---|
namespace |
Top of the hierarchy. Its labels carry forward to every resource defined in it. |
actor |
Users / service accounts. Labels carry forward to requests an actor initiates. |
connector |
The logical connector owns one label set and name shared by every definition version. |
connection |
Inherits labels and identity from its logical connector, plus the namespace. |
encryption_key |
Inherits from its namespace. |
rate_limit |
Inherits from its namespace. See Rate limits. |
request_log entry |
The frozen label snapshot of the request that produced it. |
Request log entries store the per-request label snapshot (the values that were active when the request ran), not a live reference — so a label change on the connection does not retroactively change old log entries.
Label vs. annotation
Section titled “Label vs. annotation”Both labels and annotations are key-value data. The differences are operational:
| Labels | Annotations | |
|---|---|---|
| Purpose | Identification, selection | Arbitrary metadata, descriptions |
| Selectable? | Yes — label selectors filter list queries | No |
| Key format | DNS-subdomain prefix + name (max 253 + 63 chars) | Same prefix rules but values are unrestricted |
| Value format | Up to 63 chars, alphanumeric + -_. |
Anything — up to a 256 KB total cap per resource |
| Carry forward? | Yes (see below) | No |
Use labels for things you’ll search by. Use annotations for things you want to attach but never filter on (long descriptions, ticket links, ownership emails, etc.).
System labels — the apxy/ namespace
Section titled “System labels — the apxy/ namespace”The apxy/ prefix is reserved. User-written labels under that prefix are
rejected at validation; in exchange, AuthProxy auto-populates a small set of
system labels on every resource so consumers can locate, join, and filter by
structural identity.
Identifier labels
Section titled “Identifier labels”Every resource gets three implicit labels stamped on create and refreshed on update:
| Label key | Value |
|---|---|
apxy/<rt>/-/id |
This resource’s id |
apxy/<rt>/-/name |
This resource’s current name |
apxy/<rt>/-/ns |
This resource’s namespace path |
The <rt> token comes from the resource’s apid prefix (strip the trailing _):
| Resource | <rt> |
|---|---|
| Namespace | ns |
| Actor | act |
| Connection | cxn |
| Connector | cxr |
| Key | key |
| Rate limit | rl |
For example, a connection with id cxn_abc123 in namespace root.acme always carries:
apxy/cxn/-/id: cxn_abc123apxy/cxn/-/name: production-crmapxy/cxn/-/ns: root.acmeFor namespaces, apxy/ns/-/id and apxy/ns/-/ns contain the full path while
apxy/ns/-/name contains its final segment. Connector identity labels use the
logical connector’s ID and name, so every connector version projects the same
apxy/cxr/-/name value.
These labels are useful for selecting a resource by ID or name from a
per-request snapshot and for joining audit data across resources. The normal
API name filter queries the first-class name column directly; it does not rely
on this label mirror.
Carry-forward labels
Section titled “Carry-forward labels”AuthProxy automatically carries forward labels from parent entities to the child entities. So labels from a connector are applied to connections created from that connector (with the-rekeying rules defined below). The purpose of this is to provide a flexible system where labels denormalize the metatadata so you can query child items in a way that would otherwise require a join.
When a parent resource’s labels appear on a child, they are re-keyed under the parent’s resource-type token so they don’t collide with the child’s own keys. This is the central abstraction of label propagation; see the next section.
Carry-forward — how labels flow through the hierarchy
Section titled “Carry-forward — how labels flow through the hierarchy”The hierarchy looks like this:
namespace ├── actor (labels carry forward through "act/") ├── encryption_key (labels carry forward through "ns/") ├── connector (labels carry forward through "cxr/") │ └── connection (labels carry forward through "cxn/") ├── rate_limit (labels carry forward through "ns/") └── (child namespace) (labels carry forward through "ns/")The rule
Section titled “The rule”When a child resource is created, every parent’s user labels are copied onto
the child, re-keyed under apxy/<parent_rt>/<original_key>:
- Parent namespace
root.acmehas labelteam=alpha - Connection created in
root.acmegets a materialised labelapxy/ns/team=alpha - A request through that connection gets the same
apxy/ns/team=alpharecorded in its log entry
Anything already on the parent under apxy/... is forwarded as-is (no
double-prefixing). So if root.acme itself inherited apxy/ns/team=alpha
from root (which had team=alpha), the connection still ends up with
apxy/ns/team=alpha — not apxy/ns/apxy/ns/team.
Worked example
Section titled “Worked example”root labels: { env: prod } └─ root.acme labels: { team: alpha } └─ connection labels: { app.example.com/cohort: beta }The connection’s full label set after creation:
app.example.com/cohort: beta # user-setapxy/ns/team: alpha # carried from parent namespaceapxy/ns/env: prod # carried from root (transitively)apxy/cxn/-/id: cxn_… # implicit identifierapxy/cxn/-/name: production-crm # implicit mutable nameapxy/cxn/-/ns: root.acme # implicit identifierPropagation on parent change
Section titled “Propagation on parent change”Carry-forward is materialised on create — and eventually consistent afterwards. If the parent’s labels change later, the values on existing children are stale until the propagation job catches up; depending on fleet size, fan-out depth, and how rate-limited the reconciler is, that delay can be anywhere from a few seconds to several hours.
There are two propagation paths:
- Targeted refresh. Admin API mutators (e.g., updating a namespace’s labels) enqueue a background task that re-derives every descendant’s
apxy/mirror — running each row’s update in its own short transaction so concurrent reads aren’t blocked. Typical latency: seconds to a few minutes, longer for deep fan-outs. - Daily consistency checker. A scheduled job walks every resource type, compares the on-disk labels to what the carry-forward rule would compute, and corrects any drift. Belt-and-braces for the targeted refresh; the worst-case bound is “next daily run plus the time the walk itself takes” — minutes to hours.
A rename updates the resource’s own apxy/<rt>/-/name label in the same write.
Copies carried to descendants use the same eventual reconciliation paths. For
example, renaming a connector immediately changes the connector projection, then
apxy/cxr/-/name on existing connections is refreshed by the targeted job or
the daily consistency checker.
Operational implications:
- Treat carry-forward labels as eventually-consistent reads. Application logic that needs to observe a fresh parent-label change should not rely on a child’s mirrored
apxy/<parent>/...having caught up yet. - A label change on a deep namespace can fan out to many descendants. The propagation job batches updates and runs out of band; do not rely on a label change being visible to in-flight proxy requests within the next few seconds.
- Per-request label snapshots on new requests after the update reflect the parent change as soon as each individual descendant row is rewritten — so propagation progresses visibly through the fleet rather than landing atomically.
Per-request label snapshot
Section titled “Per-request label snapshot”When an application sends a request through the proxy, AuthProxy assembles a label snapshot for that request. This is what gets recorded on the request log entry and what label selectors evaluate against (e.g., the labelSelector clause on a rate limit).
The snapshot is the union of:
- The connection’s labels (which already include namespace + connector carry-forward — see above).
- The actor’s contribution, if the request was initiated by an authenticated actor. The actor’s user labels are re-keyed under
apxy/act/<key>, plus the actor’s own identity labels (apxy/act/-/id,apxy/act/-/name,apxy/act/-/ns). Otherapxy/*entries on the actor (e.g. its own namespace’sapxy/ns/*) are not forwarded — those describe the actor’s home context, not the request’s. - Per-request labels supplied by the caller in the
labelsfield of a proxy request. These are user labels only;apxy/-prefixed keys are rejected so callers can’t impersonate system labels.
The composed snapshot is then stamped onto the request log entry’s labels
field, frozen at that point in time. A later resource rename does not rewrite
past request events. New requests see the connection’s materialized labels as
they exist when the request starts, so a carried connector or namespace name
may briefly remain at its pre-rename value while reconciliation runs.
Label selectors
Section titled “Label selectors”Anywhere the API takes a labelSelector query parameter, the syntax is Kubernetes-style:
| Form | Matches |
|---|---|
key=value, key==value |
key present and equal to value |
key!=value |
key absent or present with a different value |
key |
key present (any value) |
!key |
key absent |
Combine with commas — clauses are ANDed:
app.example.com/tenant-id=tenant-42,app.example.com/env=production,!debugSelectors can target system labels too:
# Every connection in any descendant of root.acme:apxy/ns/-/id=root.acme
# Every request log entry from connections of type "salesforce":apxy/cxr/type=salesforce
# Every request log entry from the logical connector currently named salesforce:apxy/cxr/-/name=salesforceAPI surface
Section titled “API surface”Every resource that supports labels exposes the same four sub-resource endpoints, layered on top of the resource’s CRUD URLs. Substitute the resource’s URL segment (e.g., connections, rate-limits, keys):
| Method + Path | Behaviour |
|---|---|
GET /api/v1/<resource>/:id/labels |
Read all labels |
GET /api/v1/<resource>/:id/labels/:label |
Read one label by key |
PUT /api/v1/<resource>/:id/labels/:label |
Set / update one label |
DELETE /api/v1/<resource>/:id/labels/:label |
Remove one label |
Annotations have the same shape under /annotations.
The resource-level PATCH endpoint additionally supports replacing the entire user-label set in one shot via a top-level labels field. PUTs on the sub-resource path use merge semantics; PATCH on the parent with labels populated is a full replace.
System (apxy/) labels survive a full replace — only user labels are replaced.