> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fenanpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Verifying webhook

## Verifying Webhook Signatures

<Warning>
  Always verify the webhook signature to ensure the payload's integrity and authenticity.
</Warning>

Fenan Pay signs the webhook payload using a private key. To ensure that the webhook you receive is from Fenan Pay and hasn't been tampered with, verify the signature using the corresponding public key:

* Test environment: `on dashboard: settings > webhook settings > webhook_pubk_test`
* Production environment: `on dashboard: settings > webhook settings > webhook_pubk_prod`

### How Webhook Signatures Work

Fenan Pay signs the **body** using private key speified in setting. The signature is sent in the webhook's `signature` field. You should verify the integrity of the payload by comparing the provided signature with the one generated using your webhook's public key.

<Warning>
  Make sure to verify the body **as a string** (unmodified) because any changes could invalidate the signature.
</Warning>

<Info>
  The cryptographic algorithm and signing mechanism used is `SHA256withRSA` with a key length of `2048 bits`.
</Info>

### Webhook Payload Structure

| Field   | Type   | Description                                                                                                                                                                          |
| ------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `event` | string | Specifies the type of webhook notification.                                                                                                                                          |
| `body`  | string | Contains either a [PaymentIntent](/transaction/payment-intent-object#paymentintent) or [WithdrawalIntent](/api-reference/transaction) as a JSON string, depending on the event type. |
| `event` | string | Specifies the type of webhook notification. which will be found inside the body object.                                                                                              |

### Key Points to Remember

* **Signature Field**: The `signature` field contains the cryptographic signature to verify the authenticity of the webhook body.
* **body**: Ensure you verify the body **as a string**, as any modifications can lead to a failed verification.

### Example Implementations for Verifying Webhook Signatures

<Tabs>
  <Tab title="JavaScript (Node.js)">
    ```javascript theme={null}
    const crypto = require('crypto');

    function verifySignature(payload, signature, publicKey) {
      const verify = crypto.createVerify('SHA256');
      
      // Convert the payload body into a string and update the verify object
      verify.update(payload.body);
      verify.end();
      
      // Verify the signature using the provided public key
      return verify.verify(publicKey, signature, 'base64');
    }

    // Example usage
    const payload = { signature: 'example-signature', body: { event: 'payment_intent.succeeded', ...paymentIntentObject } };
    const publicKey = '-----BEGIN PUBLIC KEY-----\nyour-public-key-here\n-----END PUBLIC KEY-----'; // should be the public key from the webhook settings including the Header and Footer
    const isVerified = verifySignature(payload, signature, publicKey);

    console.log('Signature verified:', isVerified);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import base64
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import padding
    from cryptography.hazmat.primitives.serialization import load_pem_public_key

    def verify_signature(payload, signature, public_key):
        try:
            # Load the public key
            key = load_pem_public_key(public_key.encode())
            
            # Verify the signature
            key.verify(
                base64.b64decode(signature),
                payload['body'].encode(),
                padding.PKCS1v15(),
                hashes.SHA256()
            )
            return True
        except:
            return False

    # Example usage
    payload = {'signature': 'example-signature', 'body': '{"event": "payment_intent.succeeded", ...}'}
    public_key = '-----BEGIN PUBLIC KEY-----\nyour-public-key-here\n-----END PUBLIC KEY-----'
    is_verified = verify_signature(payload, payload['signature'], public_key)

    print('Signature verified:', is_verified)
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    import java.security.*;
    import java.util.Base64;

    public class WebhookVerifier {
        public static boolean verifySignature(String payload, String signature, String publicKey) {
            try {
                Signature verifier = Signature.getInstance("SHA256withRSA");
                
                // Load the public key
                byte[] publicKeyBytes = publicKey.getBytes();
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyBytes));
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PublicKey pubKey = keyFactory.generatePublic(keySpec);
                
                verifier.initVerify(pubKey);
                verifier.update(payload.getBytes());
                
                return verifier.verify(Base64.getDecoder().decode(signature));
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }

        public static void main(String[] args) {
            String payload = "{\"event\": \"payment_intent.succeeded\", ...}";
            String signature = "example-signature";
            String publicKey = "-----BEGIN PUBLIC KEY-----\nyour-public-key-here\n-----END PUBLIC KEY-----";
            
            boolean isVerified = verifySignature(payload, signature, publicKey);
            System.out.println("Signature verified: " + isVerified);
        }
    }
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    package main

    import (
        "crypto"
        "crypto/rsa"
        "crypto/sha256"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
    )

    func verifySignature(payload, signature, publicKey string) bool {
        // Decode the base64 signature
        sig, _ := base64.StdEncoding.DecodeString(signature)

        // Parse the public key
        block, _ := pem.Decode([]byte(publicKey))
        if block == nil {
            return false
        }
        pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
        if err != nil {
            return false
        }
        rsaPublicKey, ok := pubKey.(*rsa.PublicKey)
        if !ok {
            return false
        }

        // Create a SHA256 hash of the payload
        hashed := sha256.Sum256([]byte(payload))

        // Verify the signature
        err = rsa.VerifyPKCS1v15(rsaPublicKey, crypto.SHA256, hashed[:], sig)
        return err == nil
    }

    func main() {
        payload := `{"event": "payment_intent.succeeded", ...}`
        signature := "example-signature"
        publicKey := `-----BEGIN PUBLIC KEY-----
    your-public-key-here
    -----END PUBLIC KEY-----`

        isVerified := verifySignature(payload, signature, publicKey)
        fmt.Printf("Signature verified: %v\n", isVerified)
    }
    ```
  </Tab>

  <Tab title="PHP">
    ```php theme={null}
    <?php

    function verifySignature($payload, $signature, $publicKey) {
        $publicKeyResource = openssl_pkey_get_public($publicKey);
        
        if (!$publicKeyResource) {
            return false;
        }
        
        $verify = openssl_verify($payload, base64_decode($signature), $publicKeyResource, OPENSSL_ALGO_SHA256);
        
        openssl_free_key($publicKeyResource);
        
        return $verify === 1;
    }

    // Example usage
    $payload = json_encode(['event' => 'payment_intent.succeeded', /* ... */]);
    $signature = 'example-signature';
    $publicKey = "-----BEGIN PUBLIC KEY-----\nyour-public-key-here\n-----END PUBLIC KEY-----";

    $isVerified = verifySignature($payload, $signature, $publicKey);

    echo "Signature verified: " . ($isVerified ? 'true' : 'false');

    ?>
    ```
  </Tab>
</Tabs>
