Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

token-exchange-aiac: put the refusal reason in the rejection, not only the message

Open Beginner friendly
#1,570 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
go

Research direction

Start in core/plugins/tokenexchangeaiac/plugin.go at deny(), then read docs/token-exchange-aiac-plugin.md and inspect the rejection response shapes. Add the stable reason to details for each refusal and document that contract. Done when disabled and ungranted targets expose the required reason in both the plain 403 body and JSON-RPC error.data.details.

Written by the indexing model from the issue text.

Description

aiac enhancement

Background

token-exchange-aiac answers two different refusals with the same 403 policy.forbidden:

  • audience_not_granted: Keycloak has a client for the destination, but the caller is not granted it.
  • target_disabled: the destination's client is disabled, for example a quarantined service.

The reason is recorded in the session event (pctx.Record(... Reason: reason ...)), but the rejection the caller sees carries no Details: deny() in core/plugins/tokenexchangeaiac/plugin.go returns pipeline.DenyStatus(status, code, msg). Only the human-readable message tells them apart ("the destination's client is disabled" vs "this workload is not granted the destination's audience").

rossoctl/aiac's system harness must tell them apart: its quarantine test (test_failed_tool_outbound_call_denied) counts a refusal as "blocked by the quarantine" only for target_disabled. It matches the message text, a copy of the cortex string, which breaks if the message is reworded. Raised in the review of rossoctl/aiac#242.

Task

  • Put the machine-stable reason in the rejection, for example Details: {"reason": "target_disabled"} (and audience_not_granted, exchange_failed, no_token, foreign_namespace), so it reaches the caller in the plain 403 body (details) and in error.data.details of the JSON-RPC frame.
  • Document the field in docs/token-exchange-aiac-plugin.md as part of the contract.

Acceptance criteria

  • A refusal of a disabled target carries details.reason == "target_disabled"; a refusal of an ungranted target carries details.reason == "audience_not_granted", in both rejection shapes.
  • The message text is no longer the only way to tell them apart.

Follow-up on the AIAC side: key target_disabled_refusal (k8s/authbridge-rejection.py) on the reason instead of the message.

Dominant language
Go
Stars
21
Forks
43
Avg merge
14h 25m
Merged PRs (30d)
245

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rossoctl/cortex

All issues in rossoctl/cortex

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.