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

# Verifying notification signatures


Cloudinary signs all notification responses that it sends to your provided `notification_url` or `eager_notification_url` endpoint, allowing you to validate that they were not sent by a third-party. The notification includes both an `X-Cld-Signature` header and a `X-Cld-Timestamp` header for validating the notification response.

When you provide a `notification_url` or `eager_notification_url` endpoint in a method request, or if you set a global `notification_url` in the [Console Settings](https://console.cloudinary.com/console), Cloudinary includes both an `X-Cld-Signature` header and a `X-Cld-Timestamp` header with the response sent to the specified notification endpoint.

> **NOTE**: You can set a specific key as the dedicated API key for verifying all notifications programmatically via the PUT method of the Provisioning API [access key endpoint](provisioning_api#tag/access-keys), available for [Enterprise](https://cloudinary.com/pricing#pricing-enterprise) customers upon [request](https://cloudinary.com/contact?plan=enterprise).

Here's an example POST request header sent by Cloudinary:

```
POST /my_notification_endpoint HTTP/1.1
X-Cld-Timestamp: 1368881627
X-Cld-Signature: 29a383e289bc569310a8ca9899019a3167b4909e
Content-Type: application/json
```

The signature is a hexadecimal message digest (hash value) created with the SHA-1 or SHA-256 (Secure Hash Algorithm) cryptographic function. 
> **NOTE**: By default, Cloudinary supports both SHA-1 and SHA-256 digests for validation, and you can use either. The SDK methods use the SHA-1 algorithm by default, but you can use the SHA-256 algorithm instead by setting the `signature_algorithm` SDK [configuration parameter](cloudinary_sdks#configuration_parameters) to `sha256`. If you want to limit your account to allow only the SHA-256 digest for all your validations, [submit a request](https://support.cloudinary.com/hc/en-us/requests/new).

## Use Cloudinary SDKs to verify the signature

Use the Cloudinary SDK's `verify_notification_signature` method to verify the signature in the notification, and how many seconds it is valid for.

```multi
|ruby 
Cloudinary::Utils.verify_notification_signature(body, timestamp, signature, valid_for)

|php_2
SignatureVerifier::verifyNotificationSignature($body, $timestamp, $signature, $validFor);

|python
cloudinary.utils.verify_notification_signature(body, timestamp, signature, valid_for)

|nodejs
cloudinary.utils.verifyNotificationSignature(body, timestamp, signature, valid_for)

|java
NotificationRequestSignatureVerifier.verifySignature(String body, String timestamp, String signature, long secondsValidFor)

|csharp
cloudinary.Api.VerifyNotificationSignature(string body, long timestamp, string signature, int validFor)

|go
Not supported by this SDK. Use api_sign_request to manually compare returned signature value.

|cli
cld utils verify_notification_signature $body, $timestamp, $signature, $validFor
```

## Manually verify the signature

Alternatively, you can manually compare the returned signature value in the header with the value of a signature generated on your server side as follows:

1. Create a single string containing the entire response *body*
2. Append the *X-Cld-Timestamp* value on the end of the string.
3. Append your *API secret* to the end of the string. 
   > **INFO**: When dealing with multiple API keys in your product environment, it's essential to identify the appropriate key for verification. If you've established a [dedicated API key for all your webhook notifications](#dedicated_api_key_for_webhook_notifications), make sure to employ the associated `api_secret` for verification. Otherwise, use the oldest active key in your product environment.
4. Create a hexadecimal message digest (hash value) of the string using an SHA function.

For example, if the response body is `{public_id: 'sample'}`, the X-Cld-Timestamp is `1315060510`, and your API secret is `abcd`:

* Parameters to sign:
 * `{public_id: 'sample'}`
 * `1315060510`
* In a single string:
 * `{public_id: 'sample'}1315060510`
* String including the API secret that is used to create the SHA-1 signature:
 * `{public_id: 'sample'}1315060510abcd`
* SHA-1 hexadecimal result:
 * `25f7e91709c858b97d688ce8da799dedb290d9ef`

> **TIP**: You should also compare the timestamp value with the current time to make sure that the signature was generated within a reasonable amount of time (e.g., within the last 2 hours).

PHP code example for validating the notification:

```php
//Read request body
$body = file_get_contents('php://input');
$api_secret = 'replace_with_real_api_secret';

if (!validateSignature(getallheaders(), $body, $api_secret)) {
    die("Validation failed");
}
//Use the response for your needs

function validateSignature($headers, $upload_response, $api_secret)
{
    $signed_payload = $upload_response . $headers["X-Cld-Timestamp"];
        // Compute signature with SHA-1 function and compare to header value   
    if (sha1($signed_payload . $api_secret) !== $headers['X-Cld-Signature']) {
        // Signatures DON'T match
        return false;
    }
        // Compare the current time to the received timestamp
    if ($headers["X-Cld-Timestamp"] <= strtotime('-2 hours')) {
        // Signatures match, but older than 2 hours
        return false;
    }
        // Signatures match, and timestamp is valid
    return true;
}
```

> **See also**:
>
> Have a look at the [Cloudinary Signatures](signatures) quick reference for a summary of the payload string to sign for notification signatures as well as information on other use cases that may require signature generation.

## Dedicated API key for webhook notifications

If you're working with multiple API key/secret pairs in your product environment, you have the option to specify an API key that will serve as the dedicated key for verifying webhook notifications. The dedicated API key can be used for other purposes, as well. 

The benefit of selecting a dedicated key is that it provides clarity, ensuring you always know which key to use for verification. If you don't set a dedicated API key, the system employs the oldest active key in your product environment for webhook verification. 

To set the dedicated API key, navigate to the [Webhook Notifications](https://console.cloudinary.com/app/settings/webhooks) page of the Console Settings and click **Select API Key**.

Keep in mind that only one API key can be dedicated to webhook notifications. Therefore, selecting a new API key for this purpose will replace the previously designated key.

> **NOTE**: A dedicated API key can also be set programmatically via the PUT method of the Provisioning API [access key endpoint](provisioning_api#tag/access-keys), available for [Enterprise](https://cloudinary.com/pricing#pricing-enterprise) customers upon [request](https://cloudinary.com/contact?plan=enterprise)
