cancel
Showing results for 
Search instead for 
Did you mean: 

CAP: How to call remote service with same XSUAA in background job

kosmopilot
Explorer
204

I have two services A and B in different CAP apps that share the same XSUAA. I'd like service A to call the remote service B in a background job. This results in a 401 error as there is no auth token. 

  cds.spawn({}, async () => {
      const serviceB = await cds.connect.to("B"); 
      await serviceB.send("foo", {}); // 401 error
    });

Service B does have a destination configured

  "requires": {
    "B": {
      "kind": "odata",
      "model": "./srv/external/B",
      "[production]": {
        "credentials": {
          "path": "/api/",
          "destination": "b-api",
          "forwardAuthToken": true
        }
      },
  }

Remote calls to service B work as intended when initiated inside request handling, as there is an auth token to be forwarded.

serviceA.on("bar", async () => {
  const serviceB = await cds.connect.to("B");
  await serviceB.send("foo", {}); // works
});

Is there a way for CAP to handle this automatically or do I have to fetch the token manually and set it in the header?

View Entire Topic
kosmopilot
Explorer

We resolved this using a destination on the Destination service. Instead of defining the destination inside the app, the destination is created on the Destination service during deployment. While CAP can not fetch the token from the XSUAA, the Destination service can. However, this only works when the endpoint does not require app specific roles. This only handles authentication but not authorization.

 

In cds.requires:

    "B": {
      "kind": "odata",
      "model": "./srv/external/B",
      "credentials": {
        "path": "/api/",
        "[production]": { "destination": "b-api" },
        "[development]": {
          "destination": {
            "name": "b-api",
            "url": "http://localhost:4005",
            "username": "***",
            "password": "***"
          }
        }
      }
    },

 

In the mta.yaml:

  - name: a-service
    # ------------------------------------------------------------
    type: nodejs
    path: ../dist/srv/a
    parameters:
      buildpack: nodejs_buildpack
      memory: 512MB
      disk-quota: 512MB
      command: node ./node_modules/@sap/cds/bin/cds-serve --profile production
    requires:
      - name: example-db
      - name: example-uaa
      - name: example-destination
      - name: example-connectivity
    provides:
      - name: a-api
        properties:
          srv-url: ${default-url}

  - name: example-destination-content
    # ------------------------------------------------------------
    type: com.sap.application.content
    build-parameters:
      no-source: true
    requires:
      - name: example-destination
        parameters:
          content-target: true
      - name: example-uaa
        parameters:
          service-key:
            name: ${org}-${space}-example-uaa-key
    parameters:
      content:
        instance:
          existing_destinations_policy: update
          destinations:
            - Name: b-api
              URL: ~{b-api/srv-url}
              WebIDEEnabled: true
              Authentication: OAuth2ClientCredentials
              HTML5.ForwardAuthToken: false # when enabled, the ClientCredentials flow is not triggered and we need that in background jobs
              TokenServiceURLType: Dedicated
              TokenServiceInstanceName: ${org}-${space}-example-uaa
              TokenServiceKeyName: ${org}-${space}-example-uaa-key