Prepare your receiving application to receive a webhook - JWT header
Following is sample code for when you use a JWT signed header to send call data.
import com.google.common.base.Charsets; import com.nimbusds.jose.JWSVerifier; import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.security.KeyFactory; import java.security.PublicKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.X509EncodedKeySpec; import java.time.Instant; import java.util.Base64; @RestController @RequestMapping(value = "/webhook", name = "Rule engine test webhook") public class SampleWebhook { private static Logger logger = LoggerFactory.getLogger(SampleWebhook.class); @RequestMapping(value = "/sample/newCallFromGong", method = RequestMethod.POST) public void newCallFromGong(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) { try { String authorizationHeader = httpServletRequest.getHeader("Authorization"); assert !StringUtils.isBlank(authorizationHeader); JWTClaimsSet claimSet = validateAndGetTokenClaims(authorizationHeader, new RSASSAVerifier((RSAPublicKey) wrapPublicKey(Base64.getDecoder().decode(getPublicKey())))); assert httpServletRequest.getRequestURL().toString().equals(claimSet.getStringClaim("webhook_url")); String payload = IOUtils.toString(httpServletRequest.getInputStream(), Charsets.UTF_8); assert DigestUtils.sha256Hex(payload).equals(claimSet.getStringClaim("body_sha256")); logger.debug("Payload: {}", payload); } catch (Exception e) { logger.error("Failed to process new call event.", e); } } private PublicKey wrapPublicKey(byte[] keyBytes) throws Exception { X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA", "SunRsaSign"); return keyFactory.generatePublic(publicKeySpec); } private JWTClaimsSet validateAndGetTokenClaims(String jwtToken, JWSVerifier verifier) throws Exception { SignedJWT decodedJwsObject = SignedJWT.parse(jwtToken); boolean verified = decodedJwsObject.verify(verifier); if (verified) { JWTClaimsSet claims = decodedJwsObject.getJWTClaimsSet(); final Instant expirationTime = claims.getExpirationTime().toInstant(); if (Instant.now().isAfter(expirationTime)) throw new RuntimeException("Expired Token Exception"); return claims; } else { throw new RuntimeException("Invalid Signature Exception"); } } private String getPublicKey() { return "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxfj3V1rUOJJE2RBZrWSe8UAjEL6za9+XIBTdyYbEEpzmthys8qglYDX8PLimC79VjE1QK/XWmO8lTCbacYKNLRBLxh6SpF+3d6fDtg3HeaByH3iN2HhB5aEQCRbMOIiGgMEuVf1e9rdn0gBjTWYn7JWm7CHGZpA6j0RyaKqGjZVftZGhP/lmUZVJCDfS1mntd2aX738RNjU7jxCkGHYMizVSECcN0ZH3q55YW1iZjQiXcV1MHCpm3b9q8cKRVnluUwy9jwabLY4EAJI/rccg245uYivW06rAF4BOhVtnrkSebf85tRQFNH5bLdz7mI86AyUw9sA2FEW3JT2gi+qIFQIDAQAB"; } }
import SimpleHTTPServer import SocketServer import jwt import hashlib PORT = 7080 PUBLIC_KEY = "\n".join(['-----BEGIN PUBLIC KEY-----', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxfj3V1rUOJJE2RBZrWSe8UAjEL6za9+XIBTdyYbEEpzmthys8qglYDX8PLimC79VjE1QK/XWmO8lTCbacYKNLRBLxh6SpF+3d6fDtg3HeaByH3iN2HhB5aEQCRbMOIiGgMEuVf1e9rdn0gBjTWYn7JWm7CHGZpA6j0RyaKqGjZVftZGhP/lmUZVJCDfS1mntd2aX738RNjU7jxCkGHYMizVSECcN0ZH3q55YW1iZjQiXcV1MHCpm3b9q8cKRVnluUwy9jwabLY4EAJI/rccg245uYivW06rAF4BOhVtnrkSebf85tRQFNH5bLdz7mI86AyUw9sA2FEW3JT2gi+qIFQIDAQAB', '-----END PUBLIC KEY-----']) class MySimpleHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_POST(self): data_string = self.rfile.read(int(self.headers['Content-Length'])) decoded_jwt = jwt.decode(str(self.headers['Authorization']), PUBLIC_KEY, algorithms=['RS256']) m = hashlib.sha256() m.update(data_string) assert m.hexdigest() == decoded_jwt['body_sha256'], "Request body sha256 isn't equal to sha256 from jwt payload" self.end_headers() httpd = SocketServer.TCPServer(("", PORT), MySimpleHTTPRequestHandler) httpd.serve_forever()