If you allow users to upload image files, you will have to manage storage and ensure that the upload endpoints are not a security risk for your application.

To simplify this, you can use a free image management tool like ImageKit.io, which offers image upload and real-time image resizing features.

By the end of this post, you will have a working file upload demo application and a solid understanding of how to use this in your existing project. The sample project source code is hosted on Github.

imagekitio/client-side-file-upload-plain
Client-side file upload using plain Javascript. Contribute to imagekitio/client-side-file-upload-plain development by creating an account on GitHub.

Let's get started.

Create an account on ImageKit

In case you haven't already registered, create a free account on ImageKit. This forever free plan has generous storage limits, which is good enough for many small and medium scale web applications.

File upload process

ImageKit upload API is secure. To use it, you will need some authentication. Authenticating using a secret private key is straightforward when uploading files from a secure location such as your backend application. However, when uploading files directly from the client-side, the authentication has to be done by providing a signature, which can only be generated using your account's private key.

Before we write code, let's understand all the steps:

  • Your users will upload the file on the client-side (browser).
  • The client-side application will fetch a signature from your backend. The backend will generate this signature using your account's private key. The signature should never be generated on the client-side.
  • The client-side application will call ImageKit upload API with actual file content, signature, and other file upload options.
  • The upload API responds with a successful response. The client-side application can push this response on the backend.

So overall, your frontend application triggers the actual upload while your backend is responsible for generating the signature. The ImageKit handles the actual upload.

Using SDKs to simplify upload & signature generation ?

We will be using the ImageKit Javascript SDK on the client-side. It provides an easy to use wrapper around upload API. Since we need to generate a signature, we will use the  ImageKit Node.js SDK on the server-side.

Client-side code

Create a file index.html

<form action="#" onsubmit="upload(event)">
    <input type="file" id="file" />
    <input type="submit" />
</form>

Let's include the ImageKit Javascript SDK.

<form action="#" onsubmit="upload(event)">
    <input type="file" id="file" />
    <input type="submit" />
</form>
<script type="text/javascript" src="https://unpkg.com/imagekit-javascript/dist/imagekit.min.js"></script>

Let's implement the upload function. Here we will initialize the Javascript SDK and will be needing urlEndpoint, publicKey and authenticationEndpoint parameters.

Copy urlEndpoint and publicKey the developer section in your ImageKit dashboard - https://imagekit.io/dashboard#developers

We will implement authenticationEndpoint on the backend. The SDK internally makes an HTTP GET request to this endpoint and expects a JSON response with three fields, i.e. signature, token, and expire.

/* 
    SDK initialization
    authenticationEndpoint is implemented in backedn i.e. server.js file
*/
var imagekit = new ImageKit({
    publicKey: "your_public_key",
    urlEndpoint: "your_url_endpoint", // https://ik.imagekit.io/your_imagekit_id
    authenticationEndpoint: "http://localhost:3000/signature"
});

// Upload function internally uses the ImageKit.io javascript SDK
function upload(e) {
    e.preventDefault();
    var file = document.getElementById("file");
    imagekit.upload({
        file: file.files[0],
        fileName: file.files[0].name || "sample-file.jpg",
        tags: ["tag1"], // Comma seperated value of tags
        responseFields: "tags" // Comma seperated values of fields you want in response e.g. tags, isPrivateFile etc
    }, function (err, result) {
        if (err) {
            alert("Error in file upload. Check console logs for error response");
            console.log(err);
        } else {
            alert("File uploaded. Check console logs for success response");
            console.log(result);
        }
    })
}

Server-side code

We are using Node.js to create a simple HTTP server for this demo backend and implement our authentication endpoint. However, you can use any language and leverage ImageKit's server-side SDKs to generate authentication parameters required for client-side file upload.

Create a file server.js. We will use the Express framework and ImageKit Node.js SDK.

const express = require('express')
const ImageKit = require("imagekit");
const app = express();

var imagekit = new ImageKit({
  publicKey: "your_public_key",
  privateKey: "your_private_key",
  urlEndpoint: "https://ik.imagekit.io/your_imagekit_id"
});

app.get('/signature', (req, res) => {
  var authentcationParameters = imagekit.getAuthenticationParameters();
  res.send(authentcationParameters);
})

app.listen(3000, () => {
  console.log("Sample backend app listening at http://localhost:3000");
})

To initialize the ImageKit Node.js SDK, we will need publicKey, privateKey and urlEndpoint. You can get these parameters from the developer section in your ImageKit dashboard - https://imagekit.io/dashboard#developers.

The Private API Key should never be exposed in any client-side code.

Let's edit server.js to serve the index.html file we created on the root path i.e. /

const express = require('express')
const ImageKit = require("imagekit");
const fs = require('fs')
const app = express();

var imagekit = new ImageKit({
  publicKey: "your_public_key",
  privateKey: "your_private_key",
  urlEndpoint: "https://ik.imagekit.io/your_imagekit_id"
});

app.get('/signature', (req, res) => {
  var authentcationParameters = imagekit.getAuthenticationParameters();
  res.send(authentcationParameters);
})

app.get('/', (req, res) => {
  res.writeHead(200, { 'content-type': 'text/html' });
  fs.createReadStream('index.html').pipe(res);
});

app.listen(3000, () => {
  console.log("Sample backend app listening at http://localhost:3000");
})

Now run the backend server

node server.js

This will run an HTTP server on port 3000. Open http://localhost:3000 in your browser. Choose a file and upload it. Open the console to see the response object in logs like this:

Successful upload response

Summary

If you need to implement file uploading in your application and you don't want to manage storage, security, or handle actual uploading, start using ImageKit today for free. The upload API is simple to use, as we learned in this blog post. If you come across any problem while implementing this, reach out to our support team at support@imagekit.io. We will be happy to help you!