Error message "Missing required parameter - api_key"

andrewclark
andrewclark Member Posts: 2
edited June 2023 in Developer APIs

I'm attempting to do a signed upload using the Cloudinary widget. I'm creating a signature for the request on the backed in PHP using the PHP Cloudinary SDK. My backend signing code is:

$options = array(
    "cloud_name" => [*my cloud name*],
    "api_key" => [*my api key*],
    "api_secret" => [*my api secret*],
);
$timestamp = time();
$signature = Cloudinary::sign_request(
    array(
        "timestamp" => $timestamp,
        "upload_preset" =>  [*my preset requiring signed requests*],
        "folder" => "folder",
        "resource_type" => "image"
    ),
    $options
);

//...Return signature

This creates a signature correctly (as far as I can tell) and returns it to the front end at which point I can call cloudinary.createUploadWidget(...params, function) with the created signature. However, when I open this widget and attempt to upload an image, I get an error "Missing required parameter - api_key". From my understanding, the api key is not needed at all on the front end. It should only be needed on the backend when creating the signature. But I have it on the backend already and it's value (and the cloud name and api secret) are confirmed to be the correct values. What am I missing? Thank you for the help!

Edit: I just added the api key to the front end when creating the cloudinary widget and no longer see the error. Why is the api key needed on the front end? Does this not expose information that should stay confidential?

Tagged:

Answers

  • Vdeub
    Vdeub Member, Cloudinary Staff Posts: 78

    Hi Andrew,

    As mentioned here, you do need to add the api_key when doing a signed upload via the Upload Widget. The api_key and the cloud_name can be set on the frontend as it doesn't present a risk. On the contrary, the api_secret should never be set on the frontend.

    Hope that helps.

    Best,

    Loic

  • andrewclark
    andrewclark Member Posts: 2
    edited May 2023

    Thank you Vdeub for the information, I've added it to the key to the widget on the front end and have cleared this error. I am however running into another error I can't seem to solve.

    Invalid Signature 637ee00280cbd4a85751d8de8e0eff51aaa6fadc. String to sign - 'folder=<myFolder>&source=uw&timestamp=1685544025&upload_preset=<myPreset>'

    Not only is the returned signature not the one Cloudinary is expecting, but I've also been unable to replicate generating the returned signature myself using the command "echo -n 'folder=<myFolder>&source=uw&timestamp=1685544025&upload_preset=<myPreset><myAPISecret>'" in the command line as suggested by Aleksandar in this post https://support.cloudinary.com/hc/en-us/articles/203817991-How-to-generate-a-Cloudinary-signature-on-my-own-#article-comments

    I'm also letting the Cloudinary widget pass the required parameters to the signing function by setting the uploadSignature value to a function which takes 2 arguments (a callback and a params_to_sign object) which the widget automatically calls when an upload is done (this was also suggested by a member in a community forum for simplicity although I can't seem to find that discussion now).

    Frontend:

    const newWidget = cloudinary.createUploadWidget({
            cloudName: <myCloudname>,
            uploadPreset: <myPreset>,
            showPoweredBy: false,
            folder: <myFolder>,
            api_key: <myAPIKey>,
            uploadSignature: this.generateSignature,
            resourceType: 'image',
            showAdvancedOptions: true,
            singleUploadAutoClose: true
        }, (error, result) => {<handle upload>})
    
    generateSignature: function(callback, params_to_sign) {
        Ext.Ajax.request({
            method: 'POST',
            url: <pathToSigningFunction>,
            params: {
                data: params_to_sign,
            },
            success: function (response) {
                console.debug("Signing successful")
                console.debug(response)
                let signature = Ext.JSON.decode(response.responseText).signature
                console.log('signature: ' + signature)
                callback(signature)
            },
            failure: function (response) {
                console.warn("Signing Unsuccessful")
                console.debug(response.responseText)
                new Error('Signing request failed')
            }
        })
    },
    

    Backend:

    $options = array(
        'cloud_name' => <myCloudName>,
        'api_key' => <myAPIKey>,
        'api_secret' => <myAPISecret> // All confirmed to be correct values
    );
    
    $signature = Cloudinary::sign_request(
            array($post->get('data')), // Data auto passed by Cloudinary widget
            $options
        );
    //Return signature
    


    The presence of folder, source, timestamp, and upload_preset in the returned object from the signing function indicates to me the correct information is being passed by the cloudinary widget and is being signed by the sign_request function. This function also has access to my api_secret which is needed for signing, so I'm unsure what could be going wrong.

    Any help is greatly appreciated, thank you!

  • Tamara
    Tamara Member, Cloudinary Staff Posts: 124

    Hi there,

    The error string returned is the exact string it was expecting as a signature along with the API key.

    Can you please share the exact parameters that were passed for a signature generation (in params_to_sign)? please check your timestamp.

    If you can print the string before passing it to the widget that will be helpful.

    Here is a fully working example you might find helpful:

    https://cloudinary.com/documentation/upload_widget#code_explorer_signed_uploads_using_the_upload_widget

    Here are some blog posts that might be helpful

    https://support.cloudinary.com/hc/en-us/articles/203817991-How-to-generate-a-Cloudinary-signature-on-my-own-

    https://support.cloudinary.com/hc/en-us/articles/360000693852-How-to-verify-an-upload-response-signature

    Hope this helps, please let me know if you have any further questions.

    Best regards,

    Tamara