0

Below is the requirement and they provided JAva code to create JWT.

JWT token should be signed with Client Secret. Client Key, UniqueAppId (Id assigned to the app) and a GUID should be included in the payload off the token. Client secret should be UTF-8 encoded. JWT Structure:

Header.Payload.Signature
Signature: 
data = base64urlEncode( header ) + “.” + base64urlEncode( payload )
hashedData = hash( data, Encoding.UTF8.GetBytes(plainTextSecurityKey))
signature = base64urlEncode( hashedData )

Java:

public static void main(String[] args) throws UnsupportedEncodingException {
  final Instant nowInstant = Instant.now().minus(Duration.ofHours(24));
  System.out.println("Epoch second: " + nowInstant.getEpochSecond());
  final Date currentTime = Date.from(nowInstant);
  final Date expirationDate = 
  Date.from(currentTime.toInstant().plusSeconds(1000L));
  final Map<String, Object> xyzClaims = new HashMap<>();
  xyzClaims.put("ClientKey", "Client_Key");
  xyzClaims.put("UniqueAppId", "App_ID");
  xyzClaims.put("GUID", "GUID");  
  final String clientSecret = "Client_Secret";
  final String jwt = Jwts.builder()
      .setHeaderParam("typ", "JWT")
      .setClaims(xyzClaims)
      .setNotBefore(currentTime)
      .setIssuedAt(currentTime)
      .setExpiration(expirationDate)
      .setIssuer("Your_Domain")
      .setAudience("api.XYZ.com")
      .signWith(SignatureAlgorithm.HS256, clientSecret.getBytes("UTF-8"))
      .compact();
  System.out.println("JWT: " + jwt);
}

first I need to Create JWT token ,then using JWTtoken and client credentials call a 3rd party oAuth api to get JSON response (with access, refresh tokens and expiry times).

This is the requirement and I need to write this in apex to create JWT. I have written below way. But when I try to send this with username, password which client provided I'm getting the error as

 |DEBUG|Exception :PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Because I'm getting a cert error, I generated a self signed cert and mentioned in the code (commented in the code as still it is not working and giving the same error) Not sure if JWT created incorrectly or I'm missing something in the code. Client is not providing us the certificate. Please suggest ASAP.

To create JWT token:

 public static String getJWTToken() {

        String header = '{"typ": "JWT", "alg": "HS256"}';
        String JWTHeader = base64URLencode(blob.valueOf(header));        
        System.debug('JWTHeader: ' + JWTHeader);        
        Blob b = Crypto.GenerateAESKey(128);
        String h = EncodingUtil.ConvertTohex(b);
        String guid = h.SubString(0,8)+ '-' + h.SubString(8,12) + '-' + h.SubString(12,16) + '-' + h.SubString(16,20) + '-' + h.substring(20);
        System.debug(guid);        
       xyz_custom_md__mdt mdt = new xyz_custom_md__mdt();
        String qualifiedApiName== 'xyz_mdata_Prod';
        mdt =  [SELECT    Id, ClientKey__c, ClientSecret__c, UniqueAppId__c,   nbf__c,exp__c,iat__c,iss__c,aud__c,  UserId__c,Password__c,
                QualifiedApiName from xyz_custom_md__mdt  WHERE QualifiedApiName = :qualifiedApiName   LIMIT 1 ]; 
        System.debug('metadata from getToken: ' + mdt);        
        JSONGenerator gentr = JSON.createGenerator(true);
        gentr.writeStartObject(); 
        gentr.writeStringField('ClientKey', mdt.ClientKey__c);
        gentr.writeStringField('UniqueAppId', mdt.UniqueAppId__c);
        gentr.writeStringField('GUID', guid);
        gentr.writeStringField('nbf', mdt.nbf__c);
        gentr.writeStringField('exp', mdt.exp__c);
        gentr.writeStringField('iat', mdt.iat__c);
        gentr.writeStringField('iss', mdt.iss__c);
        gentr.writeStringField('aud', mdt.aud__c);        
        gentr.writeEndObject();
        String Payload = gentr.getAsString();
        String JWTPayload = base64URLencode(blob.valueOf(Payload));
        System.debug('JWTPayload: ' + JWTPayload);        
        String signatureInput = JWTHeader + '.' + JWTPayload;
        System.debug('signatureInput: ' +signatureInput);        
        String secret = mdt.ClientSecret__c;
        System.debug('signatureInput blob: ' +Blob.valueOf(signatureInput));
        System.debug('signatureInput secret blob: ' +Blob.valueOf(secret));
        Blob JWTSignature = Crypto.generateMac('HmacSHA256',    Blob.valueOf(signatureInput),EncodingUtil.base64Decode(secret) );
        System.debug('JWTsignature: ' +JWTSignature);
        System.debug('encoded JWTsignature: ' +base64URLencode(JWTSignature));
        String JWToken = signatureInput + '.' + base64URLencode(JWTSignature);
        System.debug('JWToken: ' + JWToken);        
        return JWToken;        
    }

    public static String base64URLencode(Blob input){ 
        String output = encodingUtil.base64Encode(input);
        output = output.replace('+', '-');
        output = output.replace('/', '_');
        while ( output.endsWith('=')){
            output = output.subString(0,output.length()-1);
        }
        return output;
    }

To get access token:

 public static String getAccessToken(){
        String access_token = '';
        String refresh_token = '';

       String JWToken = getJWTToken();

              if(JWToken == null ) {
            jwtResponse = 'Error while generating JWT token.';
            System.debug('----Error :'+ jwtResponse);
            return '';
        }
        try{           
            xyz_custom_md__mdt mdt = new xyz_custom_md__mdt();
            String qualifiedApiName= 'xyz_mdata_Prod';
            mdt =  [SELECT UserId__c,Password__c, QualifiedApiName      FROM xyz_custom_md__mdt 
                    WHERE QualifiedApiName = :qualifiedApiName        LIMIT 1 ];
            System.debug('metadata: ' + mdt);
            Http http = new Http();
            HttpRequest request = new HttpRequest();
                request.setEndpoint('callout:prod_xyz/getoauth');//though not required, I'm using named cred with no authentication.
            request.setMethod('POST');            
            request.setHeader('Content-Type', 'application/json');
            request.setHeader('Authorization', JWToken);
            //request.setClientCertificateName('QA_cert');
            //request.setBody('{"UserId" : "string" , "Password" : "string"}');
            JSONGenerator gen = JSON.createGenerator(true);
            gen.writeStartObject(); 
            gen.writeStringField('UserId', mdt.UserId__c);
            gen.writeStringField('Password', mdt.Password__c);
            gen.writeEndObject();
            String jsonS = gen.getAsString();
            request.setBody(jsonS);
            System.debug('-- decoderequest with body -' +request.getbody());

            HttpResponse response = http.send(request);
            System.debug('StatusCode' + response.getStatusCode() + ' ' + response.getStatus());
             System.debug('-- response -' +response.getBody());            
            if ( response.getStatusCode() == 200 ) {
                System.JSONParser parser = System.JSON.createParser(response.getBody());
                while (parser.nextToken() != null) {
                    if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'AccessToken')) {
                        parser.nextToken();
                        access_token = parser.getText();
                        System.debug('access_token: '+ access_token);
                        //break;
                    }
                    if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'RefreshToken')) {
                        parser.nextToken();
                        refresh_token = parser.getText();
                        System.debug('refresh_token: '+ refresh_token);
                        //break;
                    }
                }
            } 
        }
        catch(Exception ex)
        {  
           //jwtResponse = ex.getMessage();
         System.debug('Exception :' + ex.getMessage());
        }
 return access_token;
    }
identigral
  • 7,543
  • 29
  • 32
  • 42
SFRR
  • 1
  • 1
  • Client didn't provide any cert, For the callout, do I need to generate a CA trusted certificate?Am I creating JWT token correct? – SFRR Mar 24 '20 at 17:46
  • JWT Token code looks correct. SunCertPathBuilderException is due to SSL issues. If the server expects a SSL cert (mutual auth in SSL), then you'll need to grab a cert (or cert chain) from your client, import it correctly via Certs and Keys and then use it via setClientCertificateName(..) – identigral Mar 24 '20 at 17:50
  • Thank you for the reply but Client is not providing us cert. What do you mean by "grab a cert (or cert chain) from your client"? Sorry I'm new to this approach. Could you explain me? – SFRR Mar 25 '20 at 15:31
  • grab a cert means you'll need to talk to your Client and ask about SSL. – identigral Mar 25 '20 at 15:38
  • But without cert, when I test on Fiddler, it works fine. – SFRR Mar 25 '20 at 18:15
  • Could you also explain when do we need to go for CA trusted certificate in SF? Not for callouts? – SFRR Mar 25 '20 at 18:26
  • SSL certs for SF as a server: please read the docs . If your call works in Fiddler but doesn't work in SF, there could be lots of reasons, SSL being one of them. – identigral Mar 25 '20 at 18:47
  • I still have this unresolved regarding getting JWT. If I test the JWT in jwt.io I'm getting error Invalid Signature. In the java code it says "signWith(SignatureAlgorithm.HS256, clientSecret.getBytes("UTF-8"))" . For this I'm using in apex "Crypto.generateMac('HmacSHA256', Blob.valueOf(signatureInput),EncodingUtil.base64Decode(secret) );". I'm sending client secret in this based on the Java code but documentation says private key. Is private key is nothing but client secret or client key? Am I using the correct algorithm name correspond to java HS256? – SFRR Apr 25 '20 at 13:11
  • Private key is not the same as client secret or client key. A client secret is like a password, a private key is a piece of crypto material. See https://salesforce.stackexchange.com/questions/281049/using-jwt-when-calling-out-from-salesforce-to-third-party-api for more info on how to create a JWT in Apex. If you're still having trouble, feel free to post a new question. See How to Ask for guidelines on writing a good question. – identigral Apr 25 '20 at 19:35

0 Answers0