Skip to main content

Use Destinations To Connect To Other Systems and Services

The SAP Cloud SDK offers some basic functionality that helps with connecting to other systems and services like SAP S/4HANA Cloud. The SAP Cloud SDK introduces the general concept of a Destination which holds basic information about how to connect to such a system. That could for instance be a url, a username, and password for basic authentication or some custom headers.

This concept is integrated with the Destination Service that is available on the SAP Business Technology Platform. If the application has a service binding to this service in place the SAP Cloud SDK will provide access to these destinations.

Accessing Destinations

In general destinations are accessed through the DestinationAccessor:


This will look up the destination in the destination service if the application is running on SAP Business Technology Platform. Other sources like the environment variables are also considered.

Authentication Flows

Authentication flows like OAuth 2.0 Client Credentials and others are usually performed by the Destination Service. They are executed when querying the destination information and the resulting authorization information will be included in the response.

See the note on supported authentication flows.

Destinations are cached for 5 minutes

To minimize the runtime overhead of finding destinations, the SAP Cloud SDK uses caching to internally maintain a list of already retrieved destinations. Therefore, subsequent calls to DestinationAccessor.getDestination("my-destination"); will be served from that cache instead of performing the look up over and over again. By default, cache entries will automatically be invalidated 5 minutes after their initial creation. The caching behavior can be customized. Please refer to our section about configuring the cache configuration for more details.

Supported Authentication Flows

The SAP Cloud SDK does not implement most of the authentication flows itself. Instead, it relies on the Destination Service to perform the flows and complements it with additional steps, if necessary.

The SAP Cloud SDK recognizes the following authentication types of the SAP BTP Destination Service:

Authentication TypeParameter Name
Other Destination Sources

In some situations you may want to obtain a destination not from the Destination Service, but e.g. from the environment variables.

In that case, only NoAuthentication and BasicAuthentication are supported by default. Additionally, OAuth2ClientCredentials as well as OAuth2UserTokenExchange are available through a dedicated API.

For more details visit the sections on how to Configure HTTP Destinations for Local Deployment and Skip Destination Creation Step for Certain Authentication Types on Cloud Foundry.

Integrated Multi-Tenancy

By default, the DestinationAccessor is tenant aware. If a tenant is available, it will be used to access the destination service on behalf of that tenant. If no destination is found in the tenant-specific destination service, the SAP Cloud SDK will try to get it using the service binding of the application.

This default retrieval strategy can be overridden by passing options to the destination loader as follows:

DestinationAccessor.getLoader().tryGetDestination(destinationName, options);

See the section on destination options below.

Supported Proxy Types

Proxy TypeParameter Name

* Further reading: SAP BTP Private Link Announcement Blog Post

Decorating Destinations

Depending on the use case, one needs to wrap the accessed destination before issuing a request to a system. This is to make sure all required destination properties are correctly set before invoking the actual request.

HTTP Destinations

In case of HTTP connections one needs to wrap the retrieved destination as HttpDestination using asHttp():


This method ensures that the required destination properties are all set to make the HTTP connection. With the resulting destination instance depending on the use case one can run HTTP queries for OData or REST.

BAPI Destinations

Similarly, for BAPI endpoints you need to use asRfc():


Registering Destinations at Runtime

The SAP Cloud SDK offers convenient ways to create a destination at runtime and register it so that it will be available via DestinationAccessor.getDestination(). This is especially useful when working in a local environment. Destinations configured in the destination service are not available in a local setting and have to be mocked.

You can create a destination manually and prepare a loader for it as follows:

customHttpDestination = DefaultHttpDestination.builder("http://url")

customLoader = new DefaultDestinationLoader()


// This will now return the custom destination

By default, the DestinationAccessor is using a DestinationLoaderChain that comprises multiple loaders. These are e.g. a loader to get destinations from the destination service and a loader that reads destinations from environment variables.

The above appendDestinationLoader() will add the provided loader at the end of such a chain. That means the new loader can operate as a fallback. Use prependDestinationLoader() to add it at the beginning if you would like it to take precedence.

Lastly use setLoader() to replace all existing loaders. This is useful if you want to supply a single destination to a piece of test code.

Enabling mTLS for Application to Destination communication

To enable mTLS while communicating with the target destination, configure the security configuration option while building up your destination at runtime.

There are two ways to specify where the HTTP Security Configuration like for e.g. the certificate, private key etc. for outbound HTTP calls is determined from.

You can choose between the options SecurityConfigurationStrategy.FROM_PLATFORM or SecurityConfigurationStrategy.FROM_DESTINATION, which is the default.

customHttpDestination = DefaultHttpDestination.builder("http://url")

SecurityConfigurationStrategy.FROM_PLATFORM ensures that the security configuration is derived from the BTP CF Instance Identity.

On the other hand SecurityConfigurationStrategy.FROM_DESTINATION derives the security configuration from the destination properties.

Provide Headers for Destinations

How It Works

You can add headers that are sent for any request over destinations. You can implement custom logic that defines which headers are sent under which circumstances.

Example Use-case

Let's imagine, you want to send an API token via a request header with any calls made over any destination in your whole application.

The SAP Cloud SDK offers the interface DestinationHeaderProvider which defines the method List<Header> getHeaders(DestinationRequestContext). At runtime, while preparing an outbound request, the SAP Cloud SDK will use all implementations of that interface which have been registered via the Java ServiceLoader mechanism (see below). For each registered implementation it invokes the method getHeaders(DestinationRequestContext) and appends the returned headers to the currently prepared request.

You can also add headers to a specific destination using properties so they will be always included when calling the target system. See the relevant section below.

Implement Own Header Provider

Implement the Interface DestinationHeaderProvider

To implement your custom destination header provider, you need to implement the interface DestinationHeaderProvider. The method getHeaders provides access to the request specific context. The method argument of type DestinationRequestContext lets you access the general properties over which the currently prepared request will be issued. Depending on your logic to determine headers, you can read the following data types:

  • DestinationProperties getDestination() (e.g. the general destination name).
  • URI getRequestUri() (e.g. the request specific query parameters)

Here is one simple example implementation which returns the same header for each request:

public List<Header> getHeaders( @Nonnull final DestinationRequestContext requestContext )
final Header header = new Header("API-Token", obtainApiToken());

return Collections.singletonList(header);

Make Interface Implementation Accessible

The SAP Cloud SDK uses the Service Loader mechanism of Java to look up the DestinationHeaderProvider implementations at runtime. To let your custom implementation be found, you need to provide a configuration file as resource in the folder META-INF/services. Name this resource file as the interface and mention the fully-qualified class name of your custom implementation. You can refer to several implementations by putting their fully qualified class names on separate lines.

Place the new folder + file in your resources folder. In a Maven project the resource folder is typically src/main/resources/. For example, if your custom implementation is named ApiTokenHeaderProvider in the package com.example, the configuration should be as follows:

  • File path & name:
  • File content:

Add Headers via Destination Properties

Here is one example implementation which adds the ("key1", "value1") header to every call to the destination:

destination =
.property("URL.headers.key1", "value1")

To include headers into every call to a target system you can define them as properties on the destination. It can be a destination object that you defined in the Cloud Foundry Cockpit, or one you built in code via a destination builder. For that, call the .property() method on the destination. It expects a key-value pair with a key formatted as URL.headers.<key> and an arbitrary value string.

SAP Language Header

When communicating with an S/4HANA (Cloud) system one can send a header to request a language preference. This can be done by setting the sap-language property on the destination. The value of this property should be a valid language tag as defined in RFC 5646.

Alternatively, the SAP Cloud SDK can also dynamically send the sap-language header based on the current locale of an incoming request or the system locale. To achieve this, set a cloudsdk.dynamicSapLanguage property to true on the destination.

Provide Query Parameters for Destinations

How It Works

You can add query parameters to a specific destination using properties. They will always be included in the query string when calling the target system.

Add Query Parameters via Destination Properties

Here is one simple example implementation which adds "key1=value1" to the query string when calling the destination:

destination =
.property("URL.queries.key1", "value1")

To include query parameters in the query string when calling to a target system you can define them as properties on the destination. For that, call the .property() method on the destination. It expects a key-value pair with a key formatted as URL.headers.<key> and an arbitrary value string.

Retrieving Destinations

Get All Destinations From the Destination Service on Cloud Foundry

To fetch all destinations from the Destination Service, you need to make a call to tryGetAllDestinations. The method queries the Destination Service API and retrieves all the destinations available at the service instance and sub-account level. In case there is a destination available on both the levels with the same name, then this method prioritizes the destination at the service instance level.

Below is the sample call to tryGetAllDestinations:

Try<Iterable<ScpCfDestination>> destinations = destinationLoader.tryGetAllDestinations(options);

In the above call destinationLoader needs to be an instance of ScpCfDestinationLoader.

Configuring Timeout Durations When Querying the Destination Service on Cloud Foundry

By default, the TimeLimiter resilience pattern aborts requests to the Destination Service on Cloud Foundry after 6 seconds. If your app requires more time when fetching destinations, you may create your own ScpCfDestinationLoader instance by:

// Allow requests to take up to 10 seconds instead of just 6
DestinationLoader destinationLoader = ScpCfDestinationLoader.builder()

To disable the timeout entirely, use TimeLimiterConfiguration.disabled().


You may register your destinationLoader within the DestinationAccessor by:


That way, all future requests to the Destination Service will use the increased timeout duration.

Configuring Caching When Querying the Destination Service on Cloud Foundry

Cached Destinations respects AuthToken Validity

Although DestinationAccessor uses a cache to minimize the overhead of fetching destinations, it still respects the validity of the associated AuthToken(if applicable for the destination). If a cached destination's AuthToken is invalid, the SAP Cloud SDK will automatically fetch the destination again from the Destination Service and cache the results as long as DestinationAccessor API is used to fetch destinations.

The SAP Cloud SDK, by default, caches up to 1,000 destinations retrieved from the Destination Service on Cloud Foundry for a maximum of 5 minutes. This behavior has two implications:

  1. Application performance can be (drastically) improved by serving already known destinations from the cache instead of querying the Destination Service over and over again.
  2. Changes to destinations, for example, via the SAP BTP Cockpit, may take a while until they are reflected in the application.

Depending on the use-case, the default cache configuration might be suboptimal. Therefore, the SAP Cloud SDK offers an API for adjusting the caching behavior at application runtime.

The example below changes the cache to store more entries for a longer period of time.

ScpCfDestinationLoader.Cache.setExpiration(Duration.ofHours(2L), CacheExpirationStrategy.WHEN_CREATED);
Cache Size

Please note that the size limit does not apply to the cache for ScpCfDestinationLoader.tryGetAllDestinations().

Change Detection Mode

In case your application typically interacts with more than one destination per tenant you can significantly improve performace by enabling change detection:


This mode will ensure the current cache entries are still valid using a single request (per tenant), instead of checking for each destination individually. For a single destination this is not a benefit, but for two or more the benefit is up to 100% per additional destination. For example, if you are interacting with 5 destinations per tenant, you can expect a 3 to 4 times performance increase.

Change Detection Interval

When using change detection, the cache expiration duration configured becomes the change detection interval. As described above, this determines how quickly changes to a destination in the BTP cockpit are reflected in your application. For example, the default setting of 5 minutes ensures, that when changing a destination it will take no more than 5 minutes for the cache to detect the change.

In rare circumstances, it might make sense to disable either specific aspects of the caching behavior, or even the entire cache. For those scenarios, following APIs are available:

// cache can store an infinite amount of entries

// cache entries never expire
// note: this setting is not available when the change detection mode is enabled

// or don't cache destinations at all
Shared Cache Size

The size limit is applied across all tenants (and principals in certain cases). One tenant (with a lot of principals) might fill up the entire cache, if all destinations requested require user propagation. If the requested destination doesn't require user propagation, destinations are cached per tenant instead.


If a thousand principals of the same tenant all query a single destination requiring user propagation, the cache will be entirely filled up with destinations belonging to the same tenant.

As a consequence, existing cache entries - also those of different tenants - must be removed (evicted) from the cache to make space for the new entries.


Changing the cache configuration at runtime will lead to a recreation of the underlying cache. Hereby, all existing cache entries will be lost.

Therefore, we recommend adjusting the cache once at application startup.


For better performance, while querying for destinations with user propagation, users may provide the EXCHANGE_ONLY token exchange strategy. Refer here for more details.

Building Destination Options

You need to build a DestinationOptions object and pass it as a parameter. It defines how Destinations Service is queried. In a simple application without provider/subscriber setup, your initial configuration is as simple as:

DestinationOptions options = DestinationOptions.builder().build();
Retrieval Strategy Options

For a provider/subscriber setup, a retrieval strategy must be chosen according to your particular use case from:

  • CURRENT_TENANT (default)

Here is an example for ONLY_SUBSCRIBER option:

DestinationOptions options =
Token Exchange Options

Besides the retrieval strategy, the SAP Cloud SDK also offers a token exchange strategy that lets you change the behavior when authentication requires a user token exchange. There are four different options available:

  • FORWARD_USER_TOKEN (default)

By default, the SAP Cloud SDK checks whether the current context contains an user access token originating from the XSUAA identity service. If that's the case, then the token will be forwarded as part of the destination lookup queries. Otherwise, LOOKUP_THEN_EXCHANGE will be applied: First SAP Cloud SDK looks up the destination on the destination service and evaluates the authentication type. If the authentication type requires a user token exchange the SAP Cloud SDK immediately performs that exchange.

If you know that the destination you are about to retrieve requires a user token exchange you can improve performance by skipping the initial "look up" request like so:

DestinationOptions options =

Try<Destination> destination = DestinationAccessor.getLoader().tryGetDestination("MyDestination", options);

Accessing Destination Properties

To access destination properties in a type-safe manner, you can make use of the predefined property keys in the DestinationProperty class, which is intended to be used similarly to an enum. Use of the DestinationProperty keys avoids the need to provide your own String identifiers and expected type-casting for retrieving destination properties.

Here is an example of accessing the URI property of a destination:

Destination destination;
Option<String> uri =

Configure HTTP Destinations for Local Development Environment

When testing your app on you local development machine instead of SAP BTP, you require some configuration steps to make the destination retrieval work.

Relevant only for HTTP destinations

Check our BAPI and RFC documentation if you want to configure an RFC destination for local development.

To better understand the configuration steps, we will shortly outline how destination retrieval works when your app runs on SAP BTP.

Background: Destination Retrieval on SAP Business Technology Platform

By default, the SAP Cloud SDK uses a set of destination loaders in the following order when searching for a destination via the DestinationAccessor API

  1. Environment variable
  2. SAP BTP Destination service

Example API call looks like this:


Details and example values of a destination retrieval
  1. Lookup in the environment variable

    The first destination loader attempts to find the requested destination in the environment variable destinations. This works the same in the local development environment. For example:

"type": "HTTP",
"name": "MyDestination",
"proxyType": "Internet",
"description": "This destination rocks!",
"authentication": "BasicAuthentication",
"url": "https://URL",
"user": "USER",
"password": "PASSWORD"

You can add as many destinations as you need this way.

Authorization Token Forwarding

By adding "forwardAuthToken": "true" to your destination, you will forward the value of the Authorization header from the current request directly to the target system.

  1. Lookup via SAP BTP Destination service

    If the previous lookup was not successful, the next destination loader examines the environment variable VCAP_SERVICES to see if the SAP BTP Destination service is bound. The SAP Cloud SDK tries to fetch the destination from the SAP BTP Destination service using the given destination name.

Reaching On Premise Systems via the SAP BTP Connectivity Service In case the destination is of proxy type OnPremise, the SAP Cloud SDK performs an additional query to the SAP BTP Connectivity service. Further proxy information and an authorization token are obtained.

Automatically Inject Service bindings via Cloud Application Programming Development Kit

If you already have a SAP BTP account with all the service binding and want to leverage them in you local environment - try CAP Development Kit. The SAP Cloud SDK will do the rest of the destination retrieval job for you as described above. You will need Node.js to install CAP Development Kit by running:

npm i -g @sap/cds-dk

Now, you can start any Java app with service binding injected into your local environment by using cds bind command. The command will create a VCAP_SERVICES variable containing service keys from a Cloud Foundry space or Kubernetes cluster without storing credentials on a disk. Start your Java application similarly to the code snippet below:

cds bind --exec mvn spring-boot:run

For more details look at the official CAP documentation

Configure Destinations Manually

Destinations With Proxy Type Internet

Create the destination configuration and pass it via the environment variable destinations. Check the example below:

"type": "HTTP",
"name": "MyDestination",
"proxyType": "Internet",
"description": "This destination rocks!",
"authentication": "BasicAuthentication",
"url": "https://URL",
"user": "USER",
"password": "PASSWORD"

You can add as many destinations as you need by adding them to the JSON array.

Authorization Token Forwarding

By adding "forwardAuthToken": "true" to your destination, you will forward the value of the Authorization header from the current request directly to the target system.

Destinations With Proxy Type OnPremise

For this destination types we need to access the Destination and Connectivity services on SAP BTP. To achieve that you have to bind them and inject via CAP Development Kit. Or manually provide your VCAP_SERVIES variable.

When your Client and On-Premise Service are in the Same Network

If your local development environment and an On-Premise service are in the same network, you can use a simple HTTP destination by providing it via destinations environment variable instead of relying on the SAP BTP Connectivity service.

Create and Provide VCAP_SERVICES Variable

How to create the VCAP_SERVICES representation depends on whether the Cloud Application Programming (CAP) Model is used.

Create the file default-env.json in your project's root and supply the VCAP_SERVICES value you copied beforehand so that the file looks similar to the following shortened example:

"connectivity": [
"label": "connectivity",
"plan": "lite",
"name": "my-connectivity",
"instance_name": "my-connectivity",
"credentials": {
"xsuaa": [
"label": "xsuaa",
"plan": "space",
"name": "my-xsuaa",
"instance_name": "my-xsuaa",
"credentials": {
"destination": [
"label": "destination",
"plan": "lite",
"name": "my-destination",
"instance_name": "my-destination",
"credentials": {

Furthermore, add the dependency to your POM file:


Reach On-Premise Service from the SAP Business Application Studio

If you are developing an application in the Business Application Studio (BAS), and want to reach On-Premise systems, perform the following steps:

  1. Make sure your BAS instance is part of the same CF space as your Cloud Connector.
  2. Add properties WebIDEEnabled and HTML5.DynamicDestination to your On-Premise destination with the value true.
  3. In BAS, configure your destinations environment variable as follows:
"type": "HTTP",
"url": "http://<DESTINATION-NAME>.dest",
"ProxyHost": "localhost",
"ProxyPort": 8887

Please refer to the BAS connectivity guide created for the SAP Cloud SDK for JavaScript to get more information and a detailed description of the technical background. The information there also applies to the SAP Cloud SDK for Java.

Skip Destination Creation Step for Certain Authentication Types on Cloud Foundry

Deprecated API

The APIs mentioned below are deprecated and will be removed in version 5 of the SAP Cloud SDK, which is scheduled to be released in Q4 2023.

For certain authentication types i.e. NoAuthentication, OAuth2ClientCredentials and OAuth2UserTokenExchange there is an API that eliminates the need to manually create a destination in the CF account for connecting to services.


final Map<String, String> mapping =

The ScpCfServiceDestinationLoader.buildClientCredentialsMapping method creates a mapping for loading a destination and provides JSON paths for all required destination properties.

final HttpDestination destination =

For certain services (only SAP BTP Workflow service for now), we provide further convenience that skips the need to provide the mapping explicitly. Example:

final HttpDestination destination =

These destinations are currently not cached. Please consider re-using the obtained destination objects when using OAuth2ClientCredentials or OAuth2UserTokenExchange oo avoid unnecessary token retrievals.

Enable Access to SAP Business Technology Platform Connectivity Service

The SAP BTP connectivity service builds the connection between SAP BTP and the On-premise network. That is why it has strong built-in restrictions to allow it only to be called from within SCP. If you call the connectivity service from your local machine, you will encounter a connection timeout. We'll therefore apply port forwarding via SSH to simulate that your localhost plays the cloud app.

  • Deploy your app to the SAP BTP once.
  • Enable SSH access to your app container with the cf CLI:
cf enable-ssh app-name
cf restart app-name
  • Inspect the value of the entry connectivity of your VCAP_SERVICES and take note of the values of the fields
    • credentials.onpremise_proxy_port
    • credentials.onpremise_proxy_host

We'll refer to these values as proxy-port and proxy-host hereafter.

  • Create an SSH session to your app container with the following command and let the session opened:
cf ssh app-name -L proxy-port:proxy-host:proxy-port
  • Replace the value of the field VCAP_SERVICES.connectivity.credentials.onpremise_proxy_host in your default-env.json with localhost.

Now your local setup is ready to consume an On-premise HTTP destination.