Skip to content

bug: ensureAudienceMapper silently swallows errors, leaving scopes without mappers #348

Description

@pdettori

Problem

When the clientregistration controller registers multiple agents concurrently, ensureAudienceMapper() can fail transiently (e.g., Keycloak rate-limiting, scope not yet visible after creation). The error is silently discarded, leaving the audience scope without a protocol mapper.

User tokens then lack the required aud claim for that agent, and AuthBridge returns 401:

JWT validation failed — "aud" not satisfied

Root Cause

In audience.go, both call sites discard the error:

// Line 90 — scope already existed
_ = a.ensureAudienceMapper(ctx, token, realm, scopeID, scopeName, audience)

// Line 108 — scope just created
_ = a.ensureAudienceMapper(ctx, token, realm, scopeID, scopeName, audience)

If the mapper POST fails for any reason other than 409 Conflict (e.g., 500, network timeout, Keycloak not yet consistent), the scope is returned without a mapper and the controller considers registration complete.

Observed Behavior

On a Kind cluster with two agents registered in the same reconcile cycle:

Scope Mapper Token aud
agent-team1-weather-service-2-aud oidc-audience-mapper with spiffe://...weather-service-2 Correct
agent-team1-weather-service-aud empty — no mapper Missing → 401

Not Fixed By

PR #331 addressed the case where a mapper exists but has a stale included.custom.audience. It does not cover the case where no mapper was created at all.

Suggested Fix

  1. Propagate the error from ensureAudienceMapper so the controller requeues:
if err := a.ensureAudienceMapper(ctx, token, realm, scopeID, scopeName, audience); err != nil {
    return "", fmt.Errorf("audience scope %q created but mapper failed: %w", scopeName, err)
}
  1. Optionally add a reconcile-time check that verifies the mapper exists on the scope, and re-creates it if missing (defense in depth against Keycloak inconsistency).

Related

Assisted-By: Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghigh priorityMust be address ASAP

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions