Ad

Salesforce REST Api Using Reactor With Spring WebClient

I tried to connect Salesforce from Spring boot webclient. I have the JWT token with the below code

String header = "{\"alg\":\"RS256\"}";
String claimTemplate = "'{'\"iss\": \"{0}\", \"sub\": \"{1}\", \"aud\": \"{2}\", \"exp\": \"{3}\", \"jti\": \"{4\"'}'";

try {
  StringBuffer token = new StringBuffer();

  //Encode the JWT Header and add it to our string to sign
  token.append(Base64.encodeBase64URLSafeString(header.getBytes("UTF-8")));

  //Separate with a period
  token.append(".");

  //Create the JWT Claims Object
  String[] claimArray = new String[4];
  claimArray[0] = "3MVG99OxTyEMCQ3gNp2PjkqeZKxnmAiG1xV4oHh9AKL_rSK.BoSVPGZHQukXnVjzRgSuQqGn75NL7yfkQcyy7";
  claimArray[1] = "[email protected]";
  claimArray[2] = "https://login.salesforce.com";
  claimArray[3] = Long.toString( ( System.currentTimeMillis()/1000 ) + 300);
  claimArray[4]=<JTI>
  MessageFormat claims;
  claims = new MessageFormat(claimTemplate);
  String payload = claims.format(claimArray);
  token.append(Base64.encodeBase64URLSafeString(payload.getBytes("UTF-8")));

  KeyStore keystore = KeyStore.getInstance("JKS");
  keystore.load(new FileInputStream("./path/to/keystore.jks"), "keystorepassword".toCharArray());
  PrivateKey privateKey = (PrivateKey) keystore.getKey("certalias", "privatekeypassword".toCharArray());

  Signature signature = Signature.getInstance("SHA256withRSA");
  signature.initSign(privateKey);
  signature.update(token.toString().getBytes("UTF-8"));
  String signedPayload = Base64.encodeBase64URLSafeString(signature.sign());
  token.append(".");
  token.append(signedPayload);


    System.out.println(token.toString());
} catch (Exception e) {
        e.printStackTrace();
    }

As per Salesforce site mentioned below. I have the private key .der file in my classpath.

I have got the AuthToken with the below code.

    HttpClient client = HttpClient.create();
    ReactorClientHttpConnector conn = new ReactorClientHttpConnector(client);
WebClient web = WebClient.builder()
        .baseUrl("https://dev.salesforce.com")
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
        .clientConnector(conn).build();

Mono<Token> token = web.post()
            .uri("/services/oauth2/token")
            .body(BodyInserters.fromFormData("grant_type", "jwt-bearer")
            .with("assertion", getAuth()).exchange().flatMap(res->res.bodyToMono(Token.class));
return token;

But I am getting reactor.core.Exceptions$Reactiveexception io.netty.channel.AbstractChannel$AnnotatedConnectionException: connection timedout exception with no further information exception.

Kindly let me know what am I missing in the post Auth Token creation method.

Ad

Answer

If you view your user in SF setup, on the bottom is login history. Does it show any errors? Does it even login ok and "just" die on actual API call?

In JWT flow you aren't supposed to send to SF the whole token as Authorization header. You'd start with token, SF would send you a message back, from that message use "access_token" in subsequent calls... https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&language=en_us has even Java sample.

Ad
source: stackoverflow.com
Ad