Skip to content

A2A/MCP IAS M2M blocked: client_credentials grant not enabled on tutorials-identity app #2649

Closed

Description

@jung-thomas

Problem

The A2A IAS auth migration (#2593, PR #2643, merged to DEV) is code-complete and deployed, but the client-credentials (M2M) grant cannot be exercised because the IAS application tutorials-identity does not permit it.

Post-deploy smoke on DEV (2026-10-04):

Check Result
Agent card advertises IAS scheme + non-empty tokenUrl ✅ security: [{ias:['openid']}], tokenUrl: https://atxgsg7zi.accounts.ondemand.com/oauth2/token, no xsuaa scheme
Anonymous /a2a → 401 / JSON-RPC -32001 ✅ backend rpc-router enforces; approuter authenticationType: none is safe
IAS client-credentials token exchange ❌ HTTP 400 unsupported_grant_type — "allowed grant_types: refresh_token, authorization_code"
IAS-bearer /a2a → 200 ⛔ blocked (no token can be minted)
XSUAA-bearer /a2a → 200 (hybrid) ⛔ not yet verified

Root cause

tutorials-identity (DEV app id 17b636dd-fa87-4cd8-b0f2-0abd5f9a3042, clientid 0b1e8b56-5f5d-4ebf-a9e9-28aae2964236, credential-type: SECRET, tenant atxgsg7zi.accounts.ondemand.com) is a bundled, SAP-managed, read-only child application (inherited from "SAP Developers", provisioned by the service binding).

Verified against the IAS admin console (read-only navigation, nothing changed):

  • OpenID Connect Configuration panel → only URIs (Redirect / Back-Channel Logout / Post Logout Redirect). No grant-types field.
  • Client Authentication panel → Secrets / Certificates / JSON Web Tokens / Trust-by-Issuer/URI / Client ID Lock. No grant-types control.
  • Token endpoint rejects client_credentials across every request shape tried: secret-in-body, HTTP Basic, and Basic + scope=openid — all identical 400.

There is no admin-console toggle to enable M2M on this app. IAS client-credentials for a BTP app is governed by the service instance / binding provisioning parameters, not the UI.

Important: MCP shares the same IAS app

tutorials-srv-mcp's identity binding is the same application — clientid 0b1e8b56-5f5d-4ebf-a9e9-28aae2964236, same tenant. So:

Proposed fix (binding-param, not UI)

  1. Research the exact IAS service-instance parameters that enable the technical-client / client_credentials grant for the installed identity service plan (verify against current SAP docs — do not assume).
  2. Add those parameters to the tutorials-identity resource in mta.yaml + .deploy/mta.yaml (and the MCP MTA mta-mcp.yaml if MCP needs the same), with matching DEV/PROD mtaext overlays as needed.
  3. Re-create / redeploy the IAS instance on DEV.
  4. Re-run the smoke (below). Then roll to PROD (same tenant atxgsg7zi; PROD app tutorials-identity-prod lives in the same tenant).

Smoke to re-run after fix (DEV)

# 1. mint token
POST https://atxgsg7zi.accounts.ondemand.com/oauth2/token
grant_type=client_credentials  (client_id/secret from tutorials-identity binding)
# expect 200 + access_token

# 2. three /a2a outcomes against the approuter
POST https://tutorial-system-dev-tutorials-approuter.cfapps.eu10-005.hana.ondemand.com/a2a  (JSON-RPC)
  IAS bearer   -> 200
  XSUAA bearer -> 200   (hybrid: cds.requires.auth = {kind:'ias', xsuaa:true})
  anonymous    -> 401 / -32001   (already confirmed)

# 3. agent card still advertises non-empty tokenUrl (already confirmed)

Scope note

Do not remove the XSUAA fallback until Central Joule consumers confirm cutover (hybrid mode must stay).

References

Activity

  1. jung-thomas commented on Oct 5, 2026

    @jung-thomas
    ContributorAuthor

    Findings & status

    M2M grant (both surfaces, both envs)

    The client-credentials (M2M) grant is a property of the shared tutorials-identity IAS instance's oauth2-configuration — NOT the MTA descriptor. It was enabled additively via cf update-service tutorials-identity -c '{...}' keeping the MTA's existing-service adoption (grants: client_credentials + authorization_code + authorization_code_pkce_s256 + refresh_token, public-client:true, redirect-uris). Confirmed on DEV and PROD. Runbook now in docs/developers/operations/ias-setup.md.

    Note: the IAS M2M token is a bare app token (claims app_tid/aud/azp/azpacr/exp/iat/iss/jti/sap_id_type/sub) — no scope claim (unlike XSUAA).

    Smoke results

    Surface Env anon IAS CC bearer
    /mcp-auth (#2592) DEV 401 ✅ 200 (9 tools)
    /mcp-auth (#2592) PROD 401 ✅ 200 (9 tools)
    /a2a DEV 401 ✅ 200
    /a2a PROD 401 ❌ 401 → fixed, see below

    #2592's /mcp-auth M2M gap is closed on PROD.

    PROD /a2a 401 — root cause (code bug, not config)

    Two conditions must hold for /a2a IAS auth: (1) the grant on the instance ✅, and (2) the route middleware resolving its bindings per-space. The middleware (srv/lib/a2a/ias-auth-mw.js) resolved IAS and XSUAA in one xsenv.getServices() call keyed by hardcoded instance names. PROD's XSUAA instance is xsuaa-imsprod (DEV: tutorials-xsuaa), so the name miss threw out of the combined call → /a2a degraded to a full anonymous pass-through, taking IAS-only M2M down with it. That's why DEV /a2a and PROD /mcp-auth worked but PROD /a2a didn't.

    Fix (PR #2657 → DEV): resolve IAS alone (required); resolve XSUAA independently by service label (xsuaa) with the dev name as fallback; if XSUAA absent, proceed IAS-only (never pass-through). XSUAA fallback stays wired when present.

    Scope guard respected

    XSUAA fallback is retained (hybrid mode) — not removed until Central Joule consumers confirm cutover.

    Remaining

  2. added a commit that references this issue on Oct 5, 2026
  3. added a commit that references this issue on Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions