Validating MD5 signatures for ONLYOFFICE Docs secure links

Overview

ONLYOFFICE Docs uses secure links with MD5 signatures to protect access to cached files. These links contain the md5 and expires parameters and are generated internally by the CoAuthoring service and validated via NGINX.

To validate or reproduce these MD5 hashes (e.g., for implementing your own proxy or security layer), follow the instructions below.

Generating MD5 signature

The MD5 signature is calculated using the following formula:

md5 = BASE64URL(MD5(<expires><uri><secret>))

Where:

  • <expires> is the numeric value from the expires query parameter in the URL;
  • <uri> is the full request path (without domain or query string), starting from /cache/files/...;
  • <secret> is the shared secret used by ONLYOFFICE Docs, typically set via the SECURE_LINK_SECRET environment variable or in the configuration files.

To generate the hash, follow these steps:

  1. Concatenate <expires>, <uri>, and <secret> into a single string.
  2. Compute the binary MD5 (e.g., md5($string, true) in PHP).
  3. Encode it using Base64.
  4. Convert the Base64 string to a URL-safe format by:

    • replacing + with -;
    • replacing / with _;
    • removing trailing =.

Configuring the secure link secret

The secret used to generate the secure link signature can be set in three ways:

Important All three configuration methods must use the same secret value. If the secret in local.json differs from the one in ds.conf, link validation will fail. This is a common issue after updates — make sure the values are in sync.
  • Environment variable (Docker only)

    Set an environment variable when running the container:

    SECURE_LINK_SECRET=your_secret_here
  • local.json configuration file

    Set the storage.fs.secretString parameter in the local.json file, which can be found at the following path:

    • For Windows - %ProgramFiles%\ONLYOFFICE\DocumentServer\config\local.json
    • For Linux - /etc/onlyoffice/documentserver/local.json
    • For Docker - /etc/onlyoffice/documentserver/local.json (within the Docker container)
    {
      "storage": {
        "fs": {
          "secretString": "your_secret_here"
        }
      }
    }
  • NGINX configuration file

    Set the $secure_link_secret parameter in the ds.conf file, which can be found at the following path:

    • For Windows - %ProgramFiles%\ONLYOFFICE\DocumentServer\nginx\conf\ds.conf
    • For Linux - /etc/onlyoffice/documentserver/nginx/ds.conf
    • For Docker - /etc/onlyoffice/documentserver/nginx/ds.conf (within the Docker container)
    secure_link_md5 "$secure_link_expires$uri$secure_link_secret";
    secure_link $arg_md5,$arg_expires;

Example

Let's consider the following example:

https://example.com/cache/files/data/31.172.71.235__172.18.0.2new.docx1749812378403_5169/output.docx/output.docx?md5=NS2_divLHhVBHdvvU9vbwA&expires=1749813362

Step 1. Extract the parameters

Extract the following parameters from the URL:

  • expires: "1749813362";
  • uri: "/cache/files/data/31.172.71.235__172.18.0.2new.docx1749812378403_5169/output.docx/output.docx";
  • secret: "eNk2pNcaoWYTkpR7YWxe".
Step 2. Validate MD5 using PHP

The following PHP example demonstrates how to generate and validate the MD5 signature:

<?php
$expires = "1749813362";
$uri = "/cache/files/data/31.172.71.235__172.18.0.2new.docx1749812378403_5169/output.docx/output.docx";
$secure_link_secret = "eNk2pNcaoWYTkpR7YWxe";
// Form the string:<expires><uri><secure_link_secret>
$string_to_hash = $expires . $uri . $secure_link_secret;
// Calculate MD5 hash
$md5_hash = md5($string_to_hash, true);
// Encode to Base64 (URL-safe)
$base64_hash = str_replace(
  ['+', '/', '='],
  ['-', '_', ''],
  base64_encode($md5_hash)
);
// Output the result
echo "String to hash: " . $string_to_hash . "\n";
echo "Generated MD5 hash: " . $base64_hash . "\n";
echo "Expected MD5 hash: NS2_divLHhVBHdvvU9vbwA\n";
?>
Step 3. Compare the signatures

The function calculates the following MD5 signature:

NS2_divLHhVBHdvvU9vbwA

This matches the md5 parameter in the URL. Therefore, the request is valid and can be confirmed.

Known issues

  • Always use the URI, not the full URL.
  • Make sure your secret matches the configuration.
  • Do not use the urlExpires parameter for hashing. This parameter is defined in default.json (not in local.json) and controls link lifetime configuration, not the value used in the MD5 formula. Always use the actual expires value from the URL query string.
  • Ensure Base64 encoding is URL-safe.
Article with the tag:
Browse all tags