The provided Certificate Signing Request (CSR) is invalid (Laravel)

I’m integrating phase 2 in Laravel 11. To create an invoice step-by-step process:

  • At the initial state, when the seller creates an invoice, it will first check for CSR, PEM, and the conf file. If not found, then it will create all the files csr, pem, and conf.
  • Then I found this error (from the laravel log):
    {“error”:“{\“errorCode\”:\“400\”,\“errorCategory\”:\“Invalid-CSR\”,\“errorMessage\”:\“The provided Certificate Signing Request (CSR) is invalid.\”}”}
  • So, my process wast, If my csr as valid, then instant it will move forward for another process to create ‘csid’ and ‘secret’. Though I’m using the seperate service function for it. but my error is showing that, ‘csr is invalid’ that’s why it’s moving forward for next steps.

Here is my code how I’m generating the keys (laravel):

    private static function generateKeysAndCsr(ZatcaSetting $settings, string $environment = 'simulation' ): void
    {
        $certsDir = storage_path('app/certs');

        if (!is_dir($certsDir)) {
            mkdir($certsDir, 0755, true);
        }

        $configPath = $certsDir . '/zatca_openssl.cnf';

        // ✅ Correct OID-based template for simulation
        $templateLine = '';
        if ($environment === 'simulation') {
            $templateLine = "1.3.6.1.4.1.311.20.2 = ASN1:PRINTABLESTRING:PREZATCA-Code-Signing";
        }

        $config = <<<CFG
                [ req ]
                default_bits = 2048
                prompt = no
                default_md = sha256
                distinguished_name = dn
                req_extensions = v3_req

                [ dn ]
                C  = {$settings->country_code}
                ST = {$settings->state}
                L  = {$settings->city}
                O  = {$settings->seller_name}
                OU = {$settings->organizational_unit_name}
                CN = {$settings->vat_number}

                [ v3_req ]
                keyUsage = digitalSignature
                extendedKeyUsage = clientAuth
                $templateLine
                subjectAltName = @alt_names

                [ alt_names ]
                DNS.1 = zatca.gov.sa
                CFG;

        file_put_contents($configPath, $config);

        $privateKeyPath = $certsDir . "/{$settings->vat_number}_private.pem";
        $csrPath        = $certsDir . "/{$settings->vat_number}.csr";

        exec("openssl genrsa -out {$privateKeyPath} 2048", $o1, $r1);
        if ($r1 !== 0) {
            throw new \Exception('Private key generation failed');
        }

        // ⚠️ IMPORTANT: explicitly apply extensions
        exec(
            "openssl req -new -key {$privateKeyPath} -out {$csrPath} -config {$configPath} -reqexts v3_req",
            $o2,
            $r2
        );

        if ($r2 !== 0) {
            throw new \Exception('CSR generation failed');
        }

        $csrPem = file_get_contents($csrPath);

        $settings->update([
            'private_key_path' => $privateKeyPath,
            'csr_content'      => $csrPem,
            'csr_base64'       => base64_encode($csrPem),
        ]);
    }

From the expertise, I want to know the process about it is a perfect way to generate the keys, csid, and secret? And how can I fix this problem as a laravel developer?

Currently, I’m stuck on these steps and still not moving forward for api submission.
Need urgent help!!

Invalid CSR can occur both during the CCSID Request and the PCSID Request, depending on how it is created.

From your code, it looks like you are using the OpenSSL CLI to generate the PrivateKey and CSR with the zatca_openssl.cnf configuration file.

You need to ensure that the contents of your configuration file follow the correct format.
Pay close attention to each line. Below is an example of the configuration file I use, which is valid for both CCSID and PCSID Requests in Sandbox, Simulation, and Production environments.

oid_section = OIDs
[OIDs]
certificateTemplateName=1.3.6.1.4.1.311.20.2

[req]
default_bits = 2048
req_extensions = v3_req
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[dn]
CN=CRN-1010010000-399999999900003
OU=Riyadh Branch
O=Maximum Speed Tech Supply LTD
C=SA

[v3_req]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment

[req_ext]
certificateTemplateName = ASN1:PRINTABLESTRING:TSTZATCA-Code-Signing
subjectAltName = dirName:alt_names

[alt_names]
SN=1-TST|2-TST|3-3F7B0F48-2091-497F-8C0D-5336C5141E97
UID=399999999900003
title=1100
registeredAddress=RRRD2929
businessCategory=Supply activities


I do not have knowledge of Laravel, but perhaps the sample PHP code in this repository could serve as a useful reference.

Hopefully, this example can be applied and serve as a solution to your problem.