FAPI- Private Key JWT

When FAPI_CertEAI authenticates a client with MTLS, client_assertion STS chain is not triggered as the client is already authenticated.

The following code snippet triggers client_assertion STS Chain. This ensures client present in client_assertion and MTLS authenticated client matches. To achieve FAPI certification with Private Key JWT, add the following snippet to the API Protection Definition pre token mapping rule:

/*
 * FAPI - Private_key_jwt
 * 
 * Ensure this snippet is added within the isFapiCompliantByDefinitionID check
 * Client Assertion is a form of client authentication. In the case of FAPI, FAPI_CertEAI authenticates a client if mtls client certificate is present. 
 * Therefore, client_assertion is not handled. This code snippet triggeres client_assertion manually and ensures client id of client_assertion jwt and client object created
 * based of mtls authentication matches.
 *
 * client_assertion_required flag enforces client_assertion. 
 *
 */
​
var client_assertion_required = true;
var client_assertion = stsuu.getContextAttributes().getAttributeValueByName("client_assertion");
​
if (client_assertion_required && request_type == "access_token" && client_assertion != null){
​
	var base_token = IDMappingExtUtils.stringToXMLElement(
	  "<wss:BinarySecurityToken "
	+ "xmlns:wss=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " 
	+ "wss:EncodingType=\"http://ibm.com/2004/01/itfim/base64encode\" "
	+ "wss:ValueType=\"urn:com:ibm:JWT\">"+client_assertion+"<\/wss:BinarySecurityToken>");
​
​
	var res = LocalSTSClient.doRequest("http://schemas.xmlsoap.org/ws/2005/02/trust/Validate","https://localhost/sps/oauth/oauth20", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer:", base_token, null)
​
    if (res.errorMessage == null){
        var client_assertion_stsuu = new STSUniversalUser();
	    client_assertion_stsuu.fromXML(res.token);
		IDMappingExtUtils.traceString("FAPI Client Assertion Result: " + client_assertion_stsuu);
		
	    var claims_str = client_assertion_stsuu.getContextAttributes().getAttributeValueByNameAndType("claim_json", "urn:com:ibm:JWT");
	    var claims = JSON.parse(claims_str);
		
	    /*
	     * Check the JWT has not expired 
	     */
​
	    if ( claims.exp != undefined ){
		  var expDate = new Date(claims.exp * 1000); 
		  var currDate = new Date();
		  if (expDate < currDate){
			   OAuthMappingExtUtils.throwSTSCustomUserPageException("JWT has expired.",400,"invalid_request");
			  }	    }   
		/*
		 * Validates aud and issuer value in client_assertion jwt against information in definition.
		 */
		if ( claims.iss != undefined && claims.aud != undefined){
			var def_id = OAuthMappingExtUtils.getClient(claims.iss).getDefinitionID();
			var iss = OAuthMappingExtUtils.getDefinitionByID(def_id).getOidc().getIss();
			var poc = OAuthMappingExtUtils.getDefinitionByID(def_id).getOidc().getPoc();
​
			if (Array.isArray(claims.aud)){
			   var found = false;
​
			   for (var x = 0; x < claims.aud.length; x++ ){
				   if((claims.aud[x]).includes(iss) || (claims.aud[x]).includes(poc)){
						found = true;
						break;
				   }			   }			   if (!found){
				  OAuthMappingExtUtils.throwSTSCustomUserPageException("aud in request object does not match issuer of client definition.",400,"invalid_request");
			   }			}			else if( !((claims.aud).includes(iss) || (claims.aud).includes(poc))){
				OAuthMappingExtUtils.throwSTSCustomUserPageException("aud in client_assertion jwt does not match issuer of client definition.",400,"invalid_request");
			}	    }		
		/*
		 * Ensure MTLS authentication credentials present
		 */
		var fingerprint = stsuu.getAttributeValueByName("fingerprint");
		if (fingerprint == null){
			OAuthMappingExtUtils.throwSTSCustomUserPageException("mtls credentials of client is missing.",400,"invalid_request");
		}	   
​
	}else{
		OAuthMappingExtUtils.throwSTSCustomUserPageException("client_assertion failed.",400,"invalid_request");
	}​
}else if(client_assertion_required && request_type == "access_token" ){
	 OAuthMappingExtUtils.throwSTSCustomUserPageException("client_assertion is not found in token endpoint.",400,"invalid_request");   
}


Parent topic: Achieving Financial-grade API (FAPI) conformance with IBM Security Verify Access