Skip to Content

Passing Dynamic Oauth Token & API Key in Header of Sender REST Adapter

Hi All,

I'm configuring sender REST Pooling to consume Ariba API. I'm passing two value 1st temporary oauth token and 2nd API Key in header filed, it's working fine. API Key is constant but token is getting expire in every 27 minutes.

I have written java code to fetch token dynamically and passing it in DynamicConfiguration, but don't know where to put access_token variable in REST Adapter.

DynamicConfiguration conf = input.getDynamicConfiguration(); DynamicConfigurationKey keyHeader1 = DynamicConfigurationKey.create("http://sap.com/xi/XI/System", "HeaderFieldOne"); conf.put(keyHeader1, "Bearer "+access_token);

Please guide me with two thing

1. Java mapping code to generate token (i have written, but need sample code to understand better)

2. How to configure token variable in sender REST adapter.

ADAPTER CONFIGURATION:-

When i select REST in Message Protocol, XI Dynamic Attribute is coming but HTTP Header tab is not there, where i will mention

Authorization Bearer {access_token}?

Appreciate your time,

Binod Kumar

1.png (16.2 kB)
2.png (23.3 kB)
3.png (17.6 kB)
Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

10 Answers

  • Apr 26 at 06:54 AM

    Since you need the token in the sender channel, it will not be possible with UDF or java mapping to achieve this requirement.

    Basically you need create custom adapter module, which will generate and store the token in the dynamic variable.

    Please check this blog for adding dynamic config variable. You have to perform look up in the adapter module and then add it to dynamic config.

    https://blogs.sap.com/2016/08/23/setting-dynamic-configuration-attributes-using-custom-adapter-module/

    Add comment
    10|10000 characters needed characters exceeded

    • Hi Muniyappan,

      Thanks for your response.

      I have to use both side sender & receiver rest adapter.

      Are we sure that to authenticate sender rest polling dynamically we have only one option "custom adapter module" ? Is there any other option for it ? Why UDF/java mapping is not possible in sender rest adapter?

      Sugata Bagchi Majumder has mentioned in above comment that he has created the Lookup to generate the token and set it to header, let him to respond.

      ----

      I want to authenticate rest adapter at receiver side as well, I saw one thread that they have mention we can do it by java mapping also.

      https://answers.sap.com/questions/386648/rest-adapter-dynamic-token-authentication.html

      One thing I'm not getting "write the token to the header of the TransformationOutput"

      how to do it, can you please help me on this ?


      Thanks again,

      Binod

  • Jan 11 at 04:09 PM
    Add comment
    10|10000 characters needed characters exceeded

    • Thanks Bhalchandra for your response, I'm not configuring in receiver rest adapter, I'm configuring in sender rest adapter.

      I have written java mapping to fetch token dynamically but where to pass the variable in sender side?

      Using 7.40, just help me with how to handle dynamic token in sender rest adapter

      Regards,

      Binod

  • Jan 21 at 11:27 PM

    Hello Binod,

    How do you invoke the java map if you want the token at sender side? not sure if an adapter module can be invoked (I tink not possible too as it requires message as Object).

    could you please elabborate your scenario?

    Thanks

    Sugata

    Add comment
    10|10000 characters needed characters exceeded

  • Jan 21 at 11:35 PM

    I have created a UDF to do REST lookup to get the token and maintained that in header

    here is the code -

    String token = "";
    StringBuffer sb = new StringBuffer();
    String party = ""; // emtpy values cannot be passed from Directory to the mapping parameters.
    Channel RESTchannel = LookupService.getChannel(party,service,channel); // parameter for component and channel from mapping in ICO
    SystemAccessor accessor = LookupService.getSystemAccessor(RESTchannel);
    getTrace().addInfo("Parameters for Token Lookup - Service: "+service+", Channel: "+channel);
    try{
    InputStream inputStream;
    String reqString = "{ \"grant_type\": \"client_credentials\" }";
    getTrace().addInfo("Request: "+reqString);
    inputStream = (InputStream) new ByteArrayInputStream(reqString.getBytes());
    com.sap.aii.mapping.lookup.Payload payload = LookupService.getXmlPayload(inputStream);
    com.sap.aii.mapping.lookup.Payload result = accessor.call(payload);
    byte[] b = new byte[4096];
    for (int n; (n = result.getContent().read(b)) != -1;){
    sb.append(new String(b,0,n));
    }
    getTrace().addDebugMessage("Response: "+sb);
    String resp = sb.toString();
    // Response handling code below depends on the response structure you are receiving
    // Below is the sample response JSON
    /*
    {
    "access_token": "3927f9ac7928bf91de26c5c93d0974dd1d9c88a7",
    "expires_in": 3600,
    "token_type": "Bearer",
    "scope": null
    }
    */
    resp = resp.replace("{","");
    resp = resp.replace("}","");
    String [] respArr = resp.split(",");
    for (int i = 0;i<respArr.length;i++)
    {
    if (respArr[i].startsWith("\"access_token\""))
    {
    int p = respArr[i].indexOf(":");
    token = respArr[i].substring(p+1);
    token = token.replace("\"","");

    }
    }
    getTrace().addInfo("Token: "+token);

    }
    catch (Exception e){
    e.printStackTrace();
    }
    finally
    {

    if (accessor!=null) accessor.close();
    }
    //return token;
    token = "access_token="+token; // Parameter replace in REST URL tab in the actual receiver REST channel
    DynamicConfiguration dynConf = (DynamicConfiguration) container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
    DynamicConfigurationKey key = DynamicConfigurationKey.create( "http://sap.com/xi/XI/System/REST", "access_token"); dynConf.put(key, token);
    return ""

    Add comment
    10|10000 characters needed characters exceeded

    • Yeah, I was not able to find where we need to put access_token variable in sender Rest adapter.

      1. For sender Rest adapter UDF is fine and in receiver we can go for java mapping & UDF is that correct ?

      2. Can you please provide brief details on how to use UDF for dynamic token with complete code? and where you're passing following details

      client_id

      client_secret

      3. Recently i came across receiver rest adapter project, i have developed standalone complete java application for that, i was not able to complete by rest adapter, PI7.40

      Let me explain you the scenario :

      1. In 1st call we will get token

      2. in 2nd call with the help of token, it generates ChunkURI

      3. In 3rd call, have to make post call on ChunkURI along with passing the file

      I tested through postman, it was working fine but through PI OMG so much horrible

      -> PI 7.40 is not able to handle token automatic

      -> any how i passed the token in header

      -> created the ChunkURI as well

      -> but last step i sucked, i created the java code for file attachment but there were no option to put dynamic variable

      If you could provide any solution for it, it would be great.

      ----------------------------

      Related to REST adapter basic question still i have

      1. what is better solution to handle dynamic token in sender & receiver side as well ??



      Lot's of thanks for your support,

      Binod

  • Feb 05 at 08:13 AM

    Hi Binod,

    You can create a OData service in your SAP gateway to call Ariba to get the data in SAP and from there you can also trigger a scenario - proxy to jdbc.

    Thanks

    Sugata

    Add comment
    10|10000 characters needed characters exceeded

  • Apr 25 at 01:37 PM

    Hello Sugata,

    Need one more help, after this i will close this thread.

    Actually above requirement got canceled but got new similar kind of requirement.

    I have tested from postman and PO Development environment, it's working fine.

    I don't know how to pass the access token to the header dynamically, I am using sender REST Pooling to fetch the data from REST based API.

    I have written java mapping code also

    public static String GenerateAccessToken() {
    
    
    		String AuthURL = "https://<host_name>/auth";
    		try {
    
    
    			URL url = new URL(AuthURL);
    			URLConnection connection = url.openConnection();
    			HttpURLConnection httpConn = (HttpURLConnection) connection;
    
    
    			// Set Header
    			httpConn.setRequestProperty("Content-Type", "application/json");
    			httpConn.setRequestProperty("Accept", "application/json");
    			httpConn.setDoOutput(true);
    			httpConn.setDoInput(true);
    			httpConn.setRequestMethod("POST");
    
    
    			// Set Body
    			String credential = "{\"username\":\"<api_user_name>\",\"password\":\"<api-password>\"}";
    
    
    			OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
    			writer.write(credential);
    			writer.close();
    
    
    			BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    			StringBuffer jsonString = new StringBuffer();
    			String line;
    			while ((line = br.readLine()) != null) {
    				jsonString.append(line);
    			}
    			br.close();
    
    
    			System.out.println(jsonString);
    			String access_token = jsonString.substring(10,jsonString.indexOf("\",\"expiration\":\""));
    
    
    			return access_token.toString();
    			
    
    
    		} catch (Exception e) {
    			throw new RuntimeException(e.getMessage());
    		}
    
    
    		// { 
                    //    "token":"access_token",
                    //      "expiration":"2019-04-23 08:39:01.000+0000"
                    // }
    
    
    	}
    
    
    
    Here I need to pass the username and password in body and Content-Type and Accept as a application/json value to generate the access token.

    Can you please guide me which one i have to used UDF/LookUP. I don't know which value have to pass in header of Sender REST Pooling adapter.

     When i see in your UDF
    
    
    //return token;
    
    token = "access_token="+token;
    DynamicConfiguration dynConf = (DynamicConfiguration) container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION); 
    
    DynamicConfigurationKey key = DynamicConfigurationKey.create( "http://sap.com/xi/XI/System/REST", "access_token"); 
    dynConf.put(key, token); return ""
    
    Which value need to provide in Header that will fetch token dynamically ?
    Since two variable is here "access_token" and "token" if we will pass token variable then what is use of access_token variable ? I am little confuse ..
    
    
    NOTE: Please help me with UDF/Lookup and explain me in detail, i am not familiar with UDF/Lookup
    
    I have one more question why we can't use java mapping here ?
    below is my logic to send token dynamically
    
    -------------
    	private static final DynamicConfigurationKey keyHeader1 = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/REST", "XHeaderName1");
    conf.put(keyHeader1, access_token);
    --------------------
    but it's throwing error ...
    
    
    Please help me ...
    
    Regards,
    Binod

    header-tab.png (2.8 kB)
    Add comment
    10|10000 characters needed characters exceeded

  • Apr 26 at 07:29 AM

    receiver side you can use java map/udf/custom adapter module.

    But in the sender, it is not the case. sender interface has get the payload, then only mapping/udf will come into picture. Hence you can not use udf/mapping here.

    Add comment
    10|10000 characters needed characters exceeded

    • Okay.

      For receiver rest adapter, below code is to send token dynamically to header.
      I have taken from existing working interface.

      public String CaptureToken(String input, Container container)throws StreamTransformationException {
      DynamicConfiguration conf = (DynamicConfiguration) container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
      if (conf != null) {
         DynamicConfigurationKey key = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/REST", "XHeaderName1");
         conf.put(key, input);
      		}
      return input;
      }
      ----------
      Note: Here input is token value that is coming from previous UDF.
      When I implement same code in java mapping to send token dynamically, it was not taking token, Unauthorized.
      Can you please check whether same code can be used in java mapping or not ?
      I am writing below code in java mapping
      ------------------------
      private static final DynamicConfigurationKey keyHeader1 = DynamicConfigurationKey.create("http://sap.com/xi/XI/System/REST", "XHeaderName1");
      DynamicConfiguration conf = arg0.getDynamicConfiguration();
      conf.put(keyHeader1, access_token);
      -------------------------
      
      Is above code is correct or do i have to modify something ?
      
      
      Regards,
      Binod
      
      
  • Apr 26 at 11:55 AM

    could you please share you channel config? what is the name being used in the channel?

    Add comment
    10|10000 characters needed characters exceeded

  • Apr 26 at 02:30 PM

    Hi,

    For receiver side, you can do it now out of the box
    https://blogs.sap.com/2019/04/25/fetch-oauth-token-in-rest-is-now-out-of-the-box/

    For sender side i still do not understand.. Basically SAP PO is generating API which you are exposing and testing from postman, so it means postman or any one calling SAP PO REST api must get a token from SAP PO am i right ?
    In that case it has to be done at system level where SAP PO system allows calls to it's end point using token

    Regards,

    Vikas

    Add comment
    10|10000 characters needed characters exceeded

  • Apr 29 at 04:19 PM

    Hi Binod,

    As Muniyappan said you have to deal this with module at sender channel. I agree with him, because you can call UDF/ java mapping once the message is in PI. But in your case you want to populate the header as soon as the message ID created in PI.
    In this case, PI will Poll the Rest end point and as soon as a message is fetched it will execute the adapter module to add the header.

    Thanks

    Sugata

    Add comment
    10|10000 characters needed characters exceeded

    • Hi Sugata & Muniyappa,

      Thanks for your response.

      So, we are confirm now sender side we have only one option that is development of "adapter module bean" ?

      Please confirm this, i will update further on this thread.

      Regards,

      Binod