Skip to Content
Technical Articles
Author's profile photo Pradeep T N

Application to Service User Token exchange

Cloud application development includes developing multi-tenant applications. Tenants or users access the application using the tenant specific URL. Multi-tenant application manages data securely per tenant without sharing one tenant information to other and is done from a single code repository.

This blog post details out how a multi-tenant application using a re-use service or a service from marketplace can exchange the user token with the consuming custom service with the tenant context in SAP cloud foundry environment.

The challenge here is application and the re-use service are deployed in different provider accounts and so the token forwarding won’t help. Also application to application  SSO also doesn’t work as they are in different accounts. So the solution proposed here makes use of OAuth to User Token Exchange flow.

Architecture

Service can be either a cloud foundry market place service or any second application which is deployed in a different provider account.

Step 1: Create the Destination

A destination of type needs to be created in the Application’s provider account and the configuration for the destination is as shown below,

URL: The url of service instance which is binded to the application

Authentication: This must be OAuth2UserTokenExchange

Client ID and Client Secret are the master client ID and Secret of the consuming service or Application (second application). In case it is market place service instance, a service key can be created and the client id and secret of the service key is used here.

OR

If it is second application in a different account then a clone of the second applicaiton’s XSUAA can be created using below API.

Clone Creation using XSUAA REST API

API URL: https://<Application2_authentication_host>/sap/rest/broker/clones?orgid=                            <Provider_Account_A_Org_ID>&serviceinstanceid=<any_name>

Method: POST
Request Body:
{
“xsappname”: “<any_name_for_clone>”
}
Authentication: Bearer token of Application2 master credentials

Token Service URL: This will be with tenant sub domain placeholder,
https://{tenant}.authentication.sap.hana.ondemand.com/oauth/token

Step 2: Create a Destination Service Instance

In the Application’s provider account space, go to Service Market Place and look for Destination Service.

Create an instance of the Destination Service with all defaults, no special configuration and bind the service instance to the Application.

Step 3: Destination look-up for token exchange

The user JWT received in the Application contains only Application specific details, like this JWT will have scope information of only current Application, so using this JWT token any other service or other application cannot be accessed. So we need to perform OAuth to User Token exchange against the consuming service or second Application. Here the destination service is used to do the token exchange.

Destination look-up HTTP API needs to be called to get the exchange token which can be used to access service or the second application whichever is configured in the destination.

Let’s first get the bearer token required to do destination look-up.

Token URL: https://<application_provider_sub_domain>.authentication.sap.hana.ondemand.com/oauth/token

Client ID: Destination Service Client ID (which you get after binding destination service to application)

Client Secret: Destination Service Secret (which you get after binding destination service to application)

Response will provide a access_token of type bearer, which is used in the next step for destination look-up.

———————————————————————————————————————-

Call below Destination Service API to do destination look-up.

URL: https://destination-configuration.cfapps.sap.hana.ondemand.com/destination-configuration/v1/destinations/<name_of_the_destination>

Authorization: Bearer token of the destination service (which we got from above step)

X-user-token: This is the additional header which has to be passed which contains the user JWT received by application

Response will look like below,

{
  "jti": "14b66fa23066414ab52d1e0ff3185120",
  "ext_attr": {
    "enhancer": "XSUAA",
    "zdn": "app-sub"
  },
  "xs.user.attributes": {},
  "granted_scopes": [
    "openid",
    "application2!b11236.App2.Administrator"
  ],
  "xs.system.attributes": {
    "xs.rolecollections": [
      "Application1Role",
      "Application2Role"
    ]
  },
  "given_name": "ABC",
  "family_name": "XYZ",
  "sub": "2dc83bee-43e9-4f25-842d-28c51a81e8bb",
  "scope": [
    "openid",
    "application2!b11236.App2.Administrator"
  ],
  "client_id": "sb-application2!b11236",
  "cid": "sb-application2!b11236",
  "azp": "sb-application2!b11236",
  "revocable": true,
  "grant_type": "user_token",
  "user_id": "2dc83bee-43e9-4f25-842d-28c51a81e8bb",
  "origin": "ldap",
  "user_name": "abc.xyz@sap.com",
  "email": "abc.xyz@sap.com",
  "auth_time": 1584941963,
  "rev_sig": "de7228a2",
  "iat": 1584941963,
  "exp": 1584985163,
  "iss": "https://app-sub.authentication.sap.hana.ondemand.com/oauth/token",
  "zid": "b09a0e51-209a-4d86-bae5-ad712f01b76c",
  "aud": []
}

Now this token which is received as response of the destination look-up can be used for accessing the consuming service or application2 with subscriber user’s context.

 

Assigned Tags

      7 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo E. Palmen
      E. Palmen

      Hi Pradeep,

      What you describing is exactly what we need.

      We are using the SAP CLOUD SDK 3.25.0 . But if we start the application it crashes.

      - com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationAccessException: Failed to get destination with name
      ‘DPG-DEST’.
      - com.sap.cloud.sdk.cloudplatform.connectivity.exception.DestinationAccessException: Failed to get destination.
      - com.sap.cloud.sdk.cloudplatform.security.exception.TokenRequestFailedException: Failed to determine cache key.
      - com.sap.cloud.sdk.cloudplatform.security.principal.exception.PrincipalAccessException: Could not read a principal from
      neither a given JWT nor a given Basic Authentication header.

       

      Given the code to execute a get query to another OData service in CF:

      final ErpHttpDestination httpDestination =
      DestinationAccessor.getDestination(destination).asHttp().decorate(DefaultErpHttpDestination::new);
      final HttpClient client = HttpClientAccessor.getHttpClient(httpDestination);
      final ODataRequestRead readRequest =
      new ODataRequestRead(url, remoteEntity, prepare(remoteEntity, ""), ODataProtocol.V4);
      final ODataRequestResultGeneric result = readRequest.execute(client);
      final Map<String, Object> resultMap = result.asMap();
      return parseToEntities((List<Map<String, Object>>) resultMap.get(“value"));

       

      Can you help or do you have a small example project.

      regards Erik

      Author's profile photo Deian Petrov
      Deian Petrov

      Hello Erik, did you solve your issue?

       

      Author's profile photo E. Palmen
      E. Palmen

      Hey Deian,

       

      No still no progress.

      Any ideas 🙂

      Author's profile photo E. Palmen
      E. Palmen

      Hey Deian,

      We have it running by using foreign-scopes.

      regards Erik

      Author's profile photo Louis Huang
      Louis Huang

      Hi. Palmen.

       

      I met the same issue as yours.

      Can you share more details or instructions about solution?

       

      Thanks a lot.

      Author's profile photo E. Palmen
      E. Palmen

      Hi Louis,

      Sorry for the late reaction.

      I followed this blog.
      https://blogs.sap.com/2020/06/02/how-to-call-protected-app-from-external-app-as-external-user-with-scope/#samplecode

      regards Erik

      Author's profile photo Rafael Zanetti
      Rafael Zanetti

      Hi!

      Thanks for this!

      I was just missing the X-user-token header name, that I could not find anywhere!

       

       

      BR,
      Rafael