- DarkLight
Prepare your receiving application to receive a webhook - JWT header
Article summary
Did you find this summary helpful?
Thank you for your feedback
Following is sample code for when you use a JWT signed header to send call data.
Java
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";
}
}
Python
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()
Was this article helpful?