I am getting an error when I try to implement einstein sentiment, this is the error: 'no protocol: IU3....OIE"'
The code stops running after I do a http.send. I am not sure what is going wrong, anyone an idea?
This is my code:
public class JWT {
public String alg {get;set;}
public String iss {get;set;}
public String sub {get;set;}
public String aud {get;set;}
public String exp {get;set;}
public String iat {get;set;}
public Map<String,String> claims {get;set;}
public Integer validFor {get;set;}
public String cert {get;set;}
public String pkcs8 {get;set;}
public String privateKey {get;set;}
public static final String HS256 = 'HS256';
public static final String RS256 = 'RS256';
public static final String NONE = 'none';
public JWT(String alg) {
this.alg = alg;
this.validFor = 300;
}
public String issue() {
String jwt = '';
JSONGenerator header = JSON.createGenerator(false);
header.writeStartObject();
header.writeStringField('alg', this.alg);
header.writeEndObject();
String encodedHeader = base64URLencode(Blob.valueOf(header.getAsString()));
JSONGenerator body = JSON.createGenerator(false);
body.writeStartObject();
body.writeStringField('iss', this.iss);
body.writeStringField('sub', this.sub);
body.writeStringField('aud', this.aud);
Long rightNow = (dateTime.now().getTime()/1000)+1;
body.writeNumberField('iat', rightNow);
body.writeNumberField('exp', (rightNow + validFor));
if (claims != null) {
for (String claim : claims.keySet()) {
body.writeStringField(claim, claims.get(claim));
}
}
body.writeEndObject();
jwt = encodedHeader + '.' + base64URLencode(Blob.valueOf(body.getAsString()));
if ( this.alg == HS256 ) {
Blob key = EncodingUtil.base64Decode(privateKey);
Blob signature = Crypto.generateMac('hmacSHA256',Blob.valueof(jwt),key);
jwt += '.' + base64URLencode(signature);
} else if ( this.alg == RS256 ) {
Blob signature = null;
if (cert != null ) {
signature = Crypto.signWithCertificate('rsa-sha256', Blob.valueOf(jwt), cert);
} else {
Blob privateKey = EncodingUtil.base64Decode(pkcs8);
signature = Crypto.sign('rsa-sha256', Blob.valueOf(jwt), privateKey);
}
jwt += '.' + base64URLencode(signature);
} else if ( this.alg == NONE ) {
jwt += '.';
}
return jwt;
}
public 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;
}
public class JWTBearerFlow {
public static String getAccessToken(String tokenEndpoint, JWT jwt) {
String access_token = null;
String body = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=' + jwt.issue();
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint(tokenEndpoint);
req.setHeader('Content-type', 'application/x-www-form-urlencoded');
req.setBody(body);
Http http = new Http();
// Code runs untill here, then error occurs
HTTPResponse res = http.send(req);
if ( res.getStatusCode() == 200 ) {
System.JSONParser parser = System.JSON.createParser(res.getBody());
while (parser.nextToken() != null) {
if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'access_token')) {
parser.nextToken();
access_token = parser.getText();
break;
}
}
}
return access_token;
}
}
public class CustomSentimentAnalysis {
@AuraEnabled
public static List<Probabilities> getCaseAnalysis(String sentimentModel , String textToAnylize){
ContentVersion base64Content = [SELECT Title, VersionData FROM ContentVersion WHERE Title = 'einstein_platform' LIMIT 1 ];
Einstein_Settings__mdt einsteinSettings = [Select DeveloperName, Label , Account_Email__c , Service_EndPoint__c , Token_EndPoint__c
from Einstein_Settings__mdt where DeveloperName ='Sentiment' Limit 1] ;
DateTime tokenExpireTime = DateTime.now().addMinutes(30);
String tokenExpireTimeinUnixFormate = ''+tokenExpireTime.getTime()/1000;
String keyContents = base64Content.VersionData.tostring();
keyContents = keyContents.replace('-----BEGIN RSA PRIVATE KEY-----', '');
keyContents = keyContents.replace('-----END RSA PRIVATE KEY-----', '');
keyContents = keyContents.replace('\n', '');
JWT jwt = new JWT('RS256');
jwt.pkcs8 = keyContents;
jwt.iss = 'developer.force.com';
jwt.sub = einsteinSettings.Account_Email__c ;
jwt.aud = einsteinSettings.Token_EndPoint__c;
jwt.exp = tokenExpireTimeinUnixFormate;
String access_token = JWTBearerFlow.getAccessToken(einsteinSettings.Token_EndPoint__c, jwt);
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint(einsteinSettings.Service_EndPoint__c);
req.setHeader('Authorization', 'Bearer ' + access_token);
req.setHeader('Content-type', 'application/json');
String body = '{\"modelId\":\"'+ sentimentModel + '\",\"document\":\"' + textToAnylize + '\"}';
req.setBody(body);
HTTPResponse res = http.send(req);
JSONParser parser = JSON.createParser(res.getBody()) ;
String label ='';
Decimal probability = 0 ;
List<Probabilities> probabilities = new List<Probabilities>() ;
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'probabilities') {
probabilities = new List<Probabilities>();
while (parser.nextToken() != JSONToken.END_ARRAY) {
probabilities.add(new Probabilities(parser));
}
}
}
}
}
return probabilities ;
}
public class Probabilities {
@AuraEnabled
public String label { get; set; }
@AuraEnabled
public Double probability { get; set; }
public Probabilities(JSONParser parser) {
while (parser.nextToken() != JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != JSONToken.VALUE_NULL) {
if (text == 'label') {
label = parser.getText();
} else if (text == 'probability') {
probability = parser.getDoubleValue();
}
}
}
}
}
}
}
tokenEndpointor not URL-encoding the output ofjwt.issue()might be the root cause. Although your JWT code looks correct, Named Credential can do most of this out of the box. – identigral Mar 10 '20 at 19:06