File Upload Using JWT Authentication

4 Dec 20246 minutes to read

JSON Web Token (JWT) is an open standard for securely transmitting information between parties as a JSON object. JWTs are commonly used for authorization, where the client includes a JWT in the request header for the server to validate before processing the request. This approach adds an extra layer of security, ensuring only authenticated users can upload or remove files.

This guide covers how to implement JWT authentication in a file upload scenario using the Uploader component in a EJ2 TypeScript app. The server is set up in .NET Core to validate the JWT token before saving or removing files.

Client-Side Setup

To set up the file uploader with JWT authentication, we’ll use the uploading and removing events of the uploader component. The asyncSettings is used to configure the URLs for saving and removing files on the server. A property named token stores the JWT.

Using the uploading and removing event argument’s, currentRequest property and setRequestHeader method, the JWT token is added to the request header during the save and remove actions.

The following code snippet provides the client-side logic for adding a JWT token during the save and remove actions.

<div class="control_wrapper">
  <input type="file" id="fileupload" name="UploadFiles" />
</div>
var dropElement = document.querySelector('.control_wrapper');

var token = 'Your.JWT.Token'; // Replace with a valid JWT token

var uploadObj: Uploader = new Uploader({
  asyncSettings: {
    saveUrl: 'https://services.syncfusion.com/js/production/api/FileUploader/Save', // Specify the endpoint URL for saving files
    removeUrl: 'https://services.syncfusion.com/js/production/api/FileUploader/Remove', // Specify the endpoint URL for removing files
  },
  uploading: onFileUploading,
  removing: onFileRemove,
  dropArea: dropElement
});
uploadObj.appendTo('#fileupload');

function onFileUploading(args) {
  // Add JWT to request header before file upload
  args.currentRequest.setRequestHeader('Authorization', `Bearer ${token}`);
}

function onFileRemove(args: RemovingEventArgs): void {
  // Add JWT to request header before file removal
  args.postRawFile = false;
  args.currentRequest.setRequestHeader('Authorization', `Bearer ${token}`);
}

Replace Your.JWT.Token with a valid JWT issued by your authentication system for production use.

Server-Side Controller (ASP.NET Core)

The server-side controller receives and validates the JWT from the request headers. If valid, the server saves or removes the file; otherwise, it returns an unauthorized response.

The Save method checks JWT authorization before saving files. If authorized, the file is saved in the Uploaded Files directory. The Remove method verifies the JWT authorization before attempting to delete a file.

The IsAuthorized method extracts and validates the JWT from the Authorization header. You can replace Your.JWT.Token with a method that verifies tokens. The SaveFileAsync method handles file saving, with support for appending data when dealing with chunked uploads.

using Microsoft.AspNetCore.Mvc;
using System.IO;
using System.Threading.Tasks;

public class HomeController : Controller
{
    private readonly string _uploads = Path.Combine(Directory.GetCurrentDirectory(), "Uploaded Files");

    public async Task<IActionResult> Save(IFormFile UploadFiles)
    {
        if (!IsAuthorized())
        {
            return Unauthorized();
        }

        if (UploadFiles == null || UploadFiles.Length == 0)
        {
            return BadRequest("Invalid file.");
        }

        Directory.CreateDirectory(_uploads);

        var filePath = Path.Combine(_uploads, UploadFiles.FileName);
        var append = UploadFiles.ContentType == "application/octet-stream"; // Handle chunk upload
        await SaveFileAsync(UploadFiles, filePath, append);

        return Ok();
    }

    private bool IsAuthorized()
    {
        var authorizationHeader = Request.Headers["Authorization"].ToString();
        if (string.IsNullOrEmpty(authorizationHeader) || !authorizationHeader.StartsWith("Bearer "))
        {
            return false;
        }
        var token = authorizationHeader["Bearer ".Length..];
        return token == "Your.JWT.Token";
    }

    private async Task SaveFileAsync(IFormFile file, string path, bool append)
    {
        await using var fileStream = new FileStream(path, append ? FileMode.Append : FileMode.Create);
        await file.CopyToAsync(fileStream);
    }

    public IActionResult Remove(string UploadFiles)
    {
        if (!IsAuthorized())
        {
            return Unauthorized();
        }

        try
        {
            var filePath = Path.Combine(_uploads, UploadFiles);
            if (System.IO.File.Exists(filePath))
            {
                System.IO.File.Delete(filePath);
                Response.StatusCode = 200;
                Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "File removed successfully";
            }
            else
            {
                Response.StatusCode = 404;
                Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "File not found";
            }
        }
        catch (Exception e)
        {
            Response.StatusCode = 500;
            Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = $"Error: {e.Message}";
        }

        return new EmptyResult();
    }
}