cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

how to inject the clientId/secret to OAuth2UserTokenExchange destination in BTP CF using MTA.yaml

TatianaFetecua
Explorer
0 Likes
2,765

Hello dear community!

I am working on a project where I have a standalone app router, and several services that I want to access from my standalone sap router.

I have been able to access my UI5/services from my approuter with no issues when I create manually a destination. I want to be able to create the destination from the mta.yaml during deployment. in my mta.yaml I added the destination like this:

 

  - name: custapp-destination
    type: org.cloudfoundry.managed-service
    requires:
     - name: srv-api
     - name: custapp-auth
       parameters:
        service-key:
         name: custapp-auth-key
    parameters:
      config: 
        HTML5Runtime_enabled: true
        init_data:
          instance:
            destinations:
            - Authentication: NoAuthentication
              Name: ui5
              ProxyType: Internet
              Type: HTTP
              URL: https://ui5.sap.com
            - Authentication:  OAuth2UserTokenExchange
              Name: custapp-api
              ProxyType: Internet
              Type: HTTP
              URL: ~{srv-api/srv-url}
              tokenServiceURL: https://XXX.authentication.XXX.hana.ondemand.com/oauth/token
              clientId: ~{custapp-auth-key}
              clientSecret: custapp-auth.clientsecret
            existing_destinations_policy: update
      service: destination
      service-plan: lite

 

unfortunately, I have been not able to find a way to dynamically determine the token serviceURL, the clientid and the clientsecret to pass it to my destination.

Is there any way to pass this values in the mta.yaml, I know that they are in the xsuaa key(custapp-auth-key).

thanks in advance for your help.

 

Tatiana F. 

Accepted Solutions (1)

Accepted Solutions (1)

Willem_Pardaens
Product and Topic Expert
Product and Topic Expert

You can use these settings to have the destination created with the credentials from the service-key:

destinations:
  - Name: custapp-api
    Authentication: OAuth2UserTokenExchange
    TokenServiceInstanceName: custapp-auth
    TokenServiceKeyName: custapp-auth-key
    URL: ~{srv-api/srv-url}
    HTML5.DynamicDestination: true
    WebIDEEnabled: true
    WebIDEUsage: odata_gen

 

TatianaFetecua
Explorer
0 Likes

Hi Willem, first thanks for your response.

I tried this. It created my destination like this:Screenshot 2024-08-23 at 9.14.52 AM.png

but this did not work from my app router, if I add manually here the clientID, Secret and token service from the custapp-auth-key it works. However, using these additional properties its not working for me.

 

Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
0 Likes

I typically don't put destination information in the init_data section of the service instance, but in a dedicated content module. I assume the content module is able to interpret the token settings whereas the init_data is not.

I suggest you create your destinations via a separate module in the mta, like this:

modules:
  - ...
  - name: custapp-destination-content
    type: com.sap.application.content
    requires:
      - name: custapp-destination
        parameters:
          content-target: true
      - name: srv-api
      - name: custapp-auth
        parameters:
          service-key:
            name: custapp-auth-key
    parameters:
      content:
        instance:
          destinations:
            - Name: custapp-api
              Authentication: OAuth2UserTokenExchange
              TokenServiceInstanceName: custapp-auth
              TokenServiceKeyName: custapp-auth-key
              URL: ~{srv-api/srv-url}
              HTML5.DynamicDestination: true
              WebIDEEnabled: true
              WebIDEUsage: odata_gen
          existing_destinations_policy: update

 

TatianaFetecua
Explorer
0 Likes

I also tried this, but it did not work either, when I tried this I get the same error that I got with the previous suggestion:

 


GET request to /custapp/odata/v4/service/cust/$metadata?sap-language=EN completed with status 500 Failed to exchange token: Request failed with status code 401 - invalid_client - Bad credentials, token details - {"subdomain":"XXX-XXX","clientId":"sb-launchpad-XXX-XXX-XXX!t999999","expiration":1724461823,"roleCollections":["Subaccount Administrator","Connectivity and Destination Administrator"]}, external service credentials details - identityzone: XXX-XX clientid: sb-clonec69da83832c64096b2ac8d7b2acc26d9XXXXXXX|destination-xsappname!b62

 

my understanding is that even that I am telling my destination to use the authorization credentials of my custapp service, it is using the credentianls of my external/standalone approuter, it is what I see at "clientId":"sb-launchpad-XXX-XXX-XXX!t99999", this clientid is the one of my standalone app router.

 

Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
0 Likes
Then something might be wrong in your project because this approach works 100%. Are you able to share the complete mta.yaml file?
TatianaFetecua
Explorer
0 Likes

yes, here is the mta.yaml of my service:

 

_schema-version: '3.1'
ID: custapp
version: 1.0.0
description: "A simple CAP project."
parameters:
  deploy_mode: html5-repo
  enable-parallel-deployments: true
build-parameters:
  before-all:
    - builder: custom
      commands:
        - npm ci
        - npx -p /cds-dk cds build --profile production
modules:
  - name: custapp-srv
    type: nodejs
    path: gen/srv
    parameters:
      buildpack: nodejs_buildpack
      readiness-health-check-type: http
      readiness-health-check-http-endpoint: /health
      disk-quota: 512M
      memory: 512M
    build-parameters:
      builder: npm
    provides:
      - name: srv-api # required by consumers of CAP services (e.g. approuter)
        properties:
          srv-url: ${default-url} 
    requires:
      - name: custapp-auth
      - name: custapp-destination
      - name: custapp-db
      - name: custapp-logging
# ----------------- HANA DB DEPLOYER  --------------------------------
  - name: custapp-db-deployer
# ------------------------------------------------------------------    
    type: hdb
    path: gen/db
    parameters:
      buildpack: nodejs_buildpack
    requires:
      - name: custapp-db
# ----------------- Destinations  --------------------------------      
  - name: custapp-destination-content
    type: com.sap.application.content
    build-parameters:
      no-source: true
    requires:
     - name: custapp-destination
       parameters:
        content-target: true
     - name: srv-api
     - name: custapp-auth
       parameters:
        service-key:
          name: custapp-auth-key
    parameters:
      content:
        instance:
         destinations:
          - Name: custapp-api
            Authentication: OAuth2UserTokenExchange
            TokenServiceInstanceName: custapp-auth
            TokenServiceKeyName: custapp-auth-key
            URL: ~{srv-api/srv-url}
            HTML5.DynamicDestination: true
            WebIDEEnabled: true
            WebIDEUsage: odata_gen
         existing_destinations_policy: update        
 # --------------------- WEBAPP CONTENT DEPLOYER ----------------------
  - name: custapp-app-content
    # ------------------------------------------------------------------
    type: com.sap.application.content
    path: .
    requires:
      - name: custapp-destination
      - name: custapp-html-repo-host
        parameters:
          content-target: true
    build-parameters:
      build-result: resources
      requires:
        - artifacts:
            - custappapp.zip
          name: custapp-app-webapp
          target-path: resources/
  # ---------------------- BOARD UI MODULE  ----------------------------
  - name: custapp-app-webapp
    # ------------------------------------------------------------------
    type: html5
    path: app/custapp-app
    build-parameters:
      build-result: dist
      builder: custom
      commands:
        - npm install
        - npm run build:cf
      supported-platforms:
        []
resources:
  - name: custapp-auth
    type: org.cloudfoundry.managed-service
    parameters:
      service: xsuaa
      service-plan: application
      path: ./xs-security.json
      config:
        xsappname: custapp-${org}-${space}
        tenant-mode: dedicated
      service-keys:  
        - name: custapp-auth-key  #need this to create the service key    
  
  - name: custapp-destination
    type: org.cloudfoundry.managed-service
    requires:
     - name: srv-api
    parameters:
      service: destination
      service-plan: lite
      config: 
        HTML5Runtime_enabled: true
        init_data:
          instance:
            existing_destinations_policy: update
            destinations:
            - Authentication: NoAuthentication
              Name: ui5
              ProxyType: Internet
              Type: HTTP
              URL: https://ui5.sap.com
  - name: custapp-db
    type: com.sap.xs.hdi-container
    parameters:
      service: hana
      service-plan: hdi-shared
    # ----------------- HTML5 REPO----------------------------------------
  - name: custapp-html-repo-host 
  # ------------------------------------------------------------------
    type: org.cloudfoundry.managed-service
    parameters:
      service: html5-apps-repo
      service-plan: app-host 
  # ---------------- APPLICATION LOGGING SERVICE ---------------
  - name: custapp-logging
    # ------------------------------------------------------------
    type: org.cloudfoundry.managed-service
    parameters:
      service: application-logs
      service-name: custapp-logging-${space}
      service-plan: lite           

 

 

and this is the mtal.yaml of my app router:

 

_schema-version: "3.1"
ID: launchpad
version: 1.0.0
description: "A simple CAP project."
parameters:
  enable-parallel-deployments: true
modules:
  - name: launchpad
    type: approuter.nodejs
    path: .
    parameters:
      keep-existing-routes: true
      disk-quota: 768M
      memory: 768M
    requires:
      - name: launchpad-approuter-auth
      - name: custapp-destination
      - name: launchpad-approuter-html5-runtime
      - name: launchpad-logging

resources:
  - name: custapp-destination
    type: org.cloudfoundry.existing-service    
  # ---------------- APPLICATION LOGGING SERVICE ---------------
  - name: launchpad-logging
    # ------------------------------------------------------------
    type: org.cloudfoundry.managed-service
    parameters:
      service: application-logs
      service-name: launchpad-logging-${space}
      service-plan: lite
  # ---------------- AUTHORIZATION SERVICE ---------------
  - name: launchpad-approuter-auth
    # ------------------------------------------------------------
    parameters:
      path: ./xs-security.json
      service-plan: application
      service: xsuaa
      config:
        xsappname: launchpad-${org}-${space}
        tenant-mode: dedicated
    type: org.cloudfoundry.managed-service
  # ---------------- HTML5 RUNTIME ---------------
  - name: launchpad-approuter-html5-runtime
    type: org.cloudfoundry.managed-service
    parameters:
      service-name: launchpad-approuter-html5-runtime
      service-plan: app-runtime
      service: html5-apps-repo

 

Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
0 Likes
Hi, your MTA's look correct to me (even though it would be simpler to share a single xsuaa instance between both the srv and approuter), but it's unclear to me what the current situation is. First we need to ensure that the destination is created correctly, not like in your first screenshot. Is that the case? And that you don't have other destinations with this name from previous tests. Then it's about ensuring the approuter uses this destination with token forwarding, so the Destination Service can do the token exchange.
TatianaFetecua
Explorer
0 Likes

Hi Willem, here is a screen shot of the recent destination, the one created with the latest mta.yaml:

Screenshot 2024-08-26 at 8.13.36 AM.png

I double checked and I do not have more destinations from previous examples, 

and here is the corresponding error that I get, trying to use the client of my external app router instead of the one in the  custapp - service

Screenshot 2024-08-26 at 8.23.42 AM.png

thanks again for looking at my problem.

 

Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
0 Likes
Ok - at least your destination seems to be created correctly now. Now it's only about the approuter and how it calls the destination. How does your xs-app.json look?
TatianaFetecua
Explorer
0 Likes

Here is my xs-app.json of my "custapp" service:

Screenshot 2024-08-26 at 1.43.07 PM.png

and this is the xs-app.json of my external approuter:

Screenshot 2024-08-26 at 2.00.17 PM.png

 

 

Willem_Pardaens
Product and Topic Expert
Product and Topic Expert
0 Likes

Sorry but your set-up is a bit complex to just understand from screenshots. Is there a reason why your project is split over 2 mta's and 2 xsuaa's? I'd suggest to simplify your approach, so the things work out-of-the-box. You should only have 1 xs-app.json because your project only has a single entry point which is your approuter: this will direct traffic either to /odata (destination) or to /app (ui) or to the login if there is no session. So all 'routes' should be defined in the approuter folder.

TatianaFetecua
Explorer

Willem thank you for your help, it is working now with the with my complex scenario where I have a service and a separated approuter(2 mta.yaml, and 2 xs-app.json), I am not sure what was the fix, but after I undeployed and delete all the instances of my external app router, and of my service and deployed it all again it worked. I also have to do a small change in one of the xs-app.json, the welcome file was: welcomeFile": "/index.html", and I changed it to welcomeFile": "index.html". Now I am able to create correctly the destination from the mta.yaml of my service.

once again thanks for the guidance!!

Answers (0)