Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 9, 2026

In Spring Security 6.5+, chaining parameter converters via addParametersConverter() causes grant_type to duplicate as a list [jwt-bearer, jwt-bearer] instead of remaining a single value, triggering AADSTS70003: unsupported grant type.

Root cause: addParametersConverter() uses MultiValueMap.addAll() which appends to existing keys. When the deprecated super.createParameters() uses parameters.add() and a chained converter also adds the same key, values accumulate into a list.

Changes

  • Reimplemented createParameters() to use parameters.set() throughout, ensuring single values
  • Removed super.createParameters() call to avoid inheritance from deprecated implementation using add()
  • Aligned with Spring Security 6.4+ pattern from DefaultOAuth2TokenRequestParametersConverter
  • Proper client authentication handling:
    • CLIENT_SECRET_BASIC: credentials in Authorization header only
    • CLIENT_SECRET_POST: credentials in POST body parameters
    • Other methods: client_id in parameters only

Before

// Calls super which uses parameters.add()
MultiValueMap<String, String> parameters = super.createParameters(request);
parameters.add("requested_token_use", "on_behalf_of");
// Result when chained: grant_type = ["jwt-bearer", "jwt-bearer"]

After

// Direct creation with parameters.set()
parameters.set(OAuth2ParameterNames.GRANT_TYPE, request.getGrantType().getValue());
parameters.set("requested_token_use", "on_behalf_of");
// Result when chained: grant_type = "jwt-bearer"
Original prompt

This section details on the original issue you should resolve

<issue_title>[BUG] On behalf of token payload is wrong in Spring boot 4.x / spring framework 7.x beta</issue_title>
<issue_description>
Describe the bug

When using the on_behalf_of grant type with Azure AD authentication, the AbstractRestClientOAuth2AccessTokenResponseClient incorrectly merges parameters from multiple converters (DefaultOAuth2TokenRequestParametersConverter and AadJwtBearerGrantRequestParameterConverter). This causes parameter values to be converted into lists instead of single values, resulting in duplicate grant type values being sent to the authorization server.

Exception or Stack Trace

[unsupported_grant_type] AADSTS70003: The app requested an unsupported grant type 'urn:ietf:params:oauth:grant-type:jwt-bearer,urn:ietf:params:oauth:grant-type:jwt-bearer'.

To Reproduce

  1. Configure a Spring Boot application with Azure AD OAuth2 authentication
  2. Set up an authorized client using the on_behalf_of grant type
  3. Attempt to request an access token using the on-behalf-of flow
  4. The request fails with the AADSTS70003 error due to malformed grant type parameter

Code Snippet

The issue occurs in the addParametersConverter() method in AbstractRestClientOAuth2AccessTokenResponseClient.java. When composing converters, the method uses MultiValueMap.addAll() which appends values to existing keys rather than replacing them:

public final void addParametersConverter(Converter<T, MultiValueMap<String, String>> parametersConverter) {
 // ... existing parameters from DefaultOAuth2TokenRequestParametersConverter
 MultiValueMap<String, String> parametersToAdd = parametersConverter.convert(authorizationGrantRequest);
 if (parametersToAdd != null) {
  parameters.addAll(parametersToAdd);  // This creates duplicate list values
 }
 return parameters;
}

Expected behavior

Parameters should be properly merged such that when multiple converters provide the same parameter key, the final value should be a single string value, not a list. The grant type should appear once as urn:ietf:params:oauth:grant-type:jwt-bearer, not duplicated.

Setup (please complete the following information):

  • OS: macOS
  • IDE: IntelliJ IDEA 2025.2.6
  • Library/Libraries: com.azure.spring:spring-cloud-azure-starter:7.0.0-beta.1
  • Java version: 25
  • Frameworks: Spring Boot 4.0.1, Spring Security with OAuth2
  • Build Tool: Maven
    </issue_description>

<agent_instructions>base on feature/springcloudazure-7.x branch</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 5 commits January 9, 2026 05:11
This commit fixes the issue where the grant_type parameter was being duplicated in the on_behalf_of token request. The problem occurred when multiple converters were chained using addParametersConverter(), which uses MultiValueMap.addAll() that appends values to existing keys instead of replacing them.

The fix reimplements createParameters() in AadJwtBearerGrantRequestEntityConverter to:
1. Use parameters.set() instead of parameters.add() to ensure single values
2. Directly create all parameters without calling the deprecated super.createParameters()
3. Follow the pattern used by Spring Security 6.4+ DefaultOAuth2TokenRequestParametersConverter

This ensures that when additional converters are added via addParametersConverter(), the grant_type remains a single value instead of being converted into a list.

Co-authored-by: Netyyyy <[email protected]>
Updated the implementation to properly handle both CLIENT_SECRET_BASIC and CLIENT_SECRET_POST authentication methods, following Spring Security 6.4+ DefaultOAuth2TokenRequestParametersConverter pattern:
- CLIENT_SECRET_BASIC: credentials sent in Authorization header (NOT in parameters)
- CLIENT_SECRET_POST: credentials sent in POST body parameters
- Other methods: only client_id in parameters

Added test to verify CLIENT_SECRET_BASIC authentication method works correctly.

Co-authored-by: Netyyyy <[email protected]>
Simplified test code by using Instant.now() directly instead of unnecessary conversions.

Co-authored-by: Netyyyy <[email protected]>
- Fixed Instant usage in noGrantTypeDuplicationWithMultipleConverters test
- Improved comments to clarify client authentication method handling

Co-authored-by: Netyyyy <[email protected]>
- Fixed typo: 'identify' → 'identity'
- Improved test assertion message to show count instead of full list

Co-authored-by: Netyyyy <[email protected]>
Copilot AI changed the title [WIP] Fix incorrect token payload merging with on behalf of grant type Fix on_behalf_of grant_type duplication in Spring Security 6.5+ Jan 9, 2026
Copilot AI requested a review from Netyyyy January 9, 2026 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] On behalf of token payload is wrong in Spring boot 4.x / spring framework 7.x beta

2 participants