diff --git a/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java b/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java
index daf6edf89..7acb8f029 100644
--- a/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java
+++ b/cloudplatform/cloudplatform-connectivity/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServiceOptions.java
@@ -324,6 +324,23 @@ public static OptionsEnhancer> withConsumerClient( @Nonnull final String consu
return new IasCommunicationOptions(null, null, null, consumerClientId, consumerTenantId);
}
+ /**
+ * Specifies the token format to request from IAS during token exchange.
+ *
+ * If not specified, the {@code token_format} parameter is not included in the token exchange request, and IAS
+ * will use its default behavior (SAML). Explicitly set to {@code "jwt"} if the target service requires JWT
+ * tokens.
+ *
+ * @param format
+ * The token format to request. Typically {@code "jwt"} or {@code "saml"}.
+ * @return An instance of {@link OptionsEnhancer} for the token format.
+ */
+ @Nonnull
+ public static OptionsEnhancer> withTokenFormat( @Nonnull final String format )
+ {
+ return new TokenFormat(format);
+ }
+
/**
* An {@link OptionsEnhancer} that contains the target URI for an IAS-based destination. Also refer to
* {@link #withTargetUri(String)}.
@@ -382,5 +399,18 @@ public IasCommunicationOptions getValue()
return this;
}
}
+
+ /**
+ * An {@link OptionsEnhancer} that specifies the token format for IAS token requests. If not provided, the
+ * {@code token_format} parameter is not included in the token exchange request. Also refer to
+ * {@link #withTokenFormat(String)}.
+ */
+ @Value
+ @AllArgsConstructor( access = AccessLevel.PRIVATE )
+ public static class TokenFormat implements OptionsEnhancer
+ {
+ @Nonnull
+ String value;
+ }
}
}
diff --git a/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java b/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java
index 2833be740..2e112c0b5 100644
--- a/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java
+++ b/cloudplatform/connectivity-oauth/src/main/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliers.java
@@ -2,6 +2,7 @@
import static com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.AuthenticationServiceOptions.TargetUri;
import static com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.IasOptions.IasCommunicationOptions;
+import static com.sap.cloud.sdk.cloudplatform.connectivity.BtpServiceOptions.IasOptions.TokenFormat;
import static com.sap.cloud.sdk.cloudplatform.connectivity.MultiUrlPropertySupplier.REMOVE_PATH;
import java.net.URI;
@@ -189,6 +190,9 @@ public OAuth2Options getOAuth2Options()
} else {
attachIasCommunicationOptions(builder);
builder.withTokenRetrievalParameter("app_tid", getCredentialOrThrow(String.class, "app_tid"));
+ options
+ .getOption(TokenFormat.class)
+ .peek(format -> builder.withTokenRetrievalParameter("token_format", format));
}
attachClientKeyStore(builder);
diff --git a/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java b/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java
index 6afd3fef1..ae9da1462 100644
--- a/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java
+++ b/cloudplatform/connectivity-oauth/src/test/java/com/sap/cloud/sdk/cloudplatform/connectivity/BtpServicePropertySuppliersTest.java
@@ -789,6 +789,75 @@ void testMutuallyExclusiveOptions()
}
}
+ @Test
+ void testTokenFormatExplicitJwt()
+ {
+ final ServiceBindingDestinationOptions options =
+ ServiceBindingDestinationOptions
+ .forService(BINDING)
+ .onBehalfOf(OnBehalfOf.NAMED_USER_CURRENT_TENANT)
+ .withOption(IasOptions.withApplicationName("app-name"))
+ .withOption(IasOptions.withTokenFormat("jwt"))
+ .build();
+
+ final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options);
+ final OAuth2Options oAuth2Options = sut.getOAuth2Options();
+
+ assertThat(oAuth2Options.getAdditionalTokenRetrievalParameters())
+ .containsExactlyInAnyOrderEntriesOf(
+ Map
+ .of(
+ "resource",
+ "urn:sap:identity:application:provider:name:app-name",
+ "app_tid",
+ PROVIDER_TENANT_ID,
+ "token_format",
+ "jwt"));
+ }
+
+ @Test
+ void testTokenFormatExplicitSaml()
+ {
+ final ServiceBindingDestinationOptions options =
+ ServiceBindingDestinationOptions
+ .forService(BINDING)
+ .onBehalfOf(OnBehalfOf.NAMED_USER_CURRENT_TENANT)
+ .withOption(IasOptions.withApplicationName("app-name"))
+ .withOption(IasOptions.withTokenFormat("saml"))
+ .build();
+
+ final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options);
+ final OAuth2Options oAuth2Options = sut.getOAuth2Options();
+
+ assertThat(oAuth2Options.getAdditionalTokenRetrievalParameters())
+ .containsExactlyInAnyOrderEntriesOf(
+ Map
+ .of(
+ "resource",
+ "urn:sap:identity:application:provider:name:app-name",
+ "app_tid",
+ PROVIDER_TENANT_ID,
+ "token_format",
+ "saml"));
+ }
+
+ @Test
+ void testTokenFormatWithoutApplicationName()
+ {
+ final ServiceBindingDestinationOptions options =
+ ServiceBindingDestinationOptions
+ .forService(BINDING)
+ .onBehalfOf(OnBehalfOf.NAMED_USER_CURRENT_TENANT)
+ .withOption(IasOptions.withTokenFormat("jwt"))
+ .build();
+
+ final OAuth2PropertySupplier sut = IDENTITY_AUTHENTICATION.resolve(options);
+ final OAuth2Options oAuth2Options = sut.getOAuth2Options();
+
+ assertThat(oAuth2Options.getAdditionalTokenRetrievalParameters())
+ .containsExactlyInAnyOrderEntriesOf(Map.of("app_tid", PROVIDER_TENANT_ID, "token_format", "jwt"));
+ }
+
@SneakyThrows
private static void assertThatClientCertificateIsContained( @Nonnull final KeyStore keyStore )
{