Skip to footer content
USING IRONPDF

How to Add PDF Digital Signatures in ASP.NET Core

Adding a digital signature to a PDF in ASP.NET Core protects document integrity, confirms the signer's identity, and makes the file legally defensible in most jurisdictions. With IronPDF, you can sign PDFs server-side using certificate files, add visible signature images, and embed interactive signature form fields -- all within a few lines of C# code.

Install the library from NuGet, grab your .pfx certificate, and follow the examples below to build a production-ready document signing workflow.

Install-Package IronPdf
dotnet add package IronPdf
Install-Package IronPdf
dotnet add package IronPdf
SHELL

You can also install it through the NuGet Package Manager inside Visual Studio, or download it directly from the IronPDF product page. Start a free trial to test all signing features with no commitment.

What Is a PDF Digital Signature and Why Does It Matter?

A digital signature is a cryptographic mechanism that binds the signer's identity to a specific version of a document. It differs from a simple electronic signature -- such as a typed name or scanned image -- because it uses public-key cryptography to create a verifiable, tamper-evident seal.

When someone digitally signs a PDF, the signing software generates a hash of the document contents and encrypts that hash with the signer's private key. The resulting signature is embedded in the PDF alongside the signer's public certificate. Any PDF reader that supports digital signatures -- including Adobe Acrobat Reader and PDF viewers built into modern browsers -- can decrypt the hash with the public key and compare it against a freshly computed hash of the document. If the hashes match, the document is authentic and unmodified.

Why Digital Signatures Are Legally Important

In most countries, digitally signed documents carry the same legal weight as hand-signed paper contracts. The eIDAS regulation in the European Union and the ESIGN Act in the United States both recognize electronic signatures as legally binding when certain conditions are met. Certificate-based digital signatures satisfy the strongest tier of those requirements.

Where Digital Signatures Fit in ASP.NET Core

Server-side signing inside an ASP.NET Core application allows you to sign documents automatically during processing -- no client software is required. Contracts, invoices, compliance reports, and NDAs can all be signed the moment they are generated, and the signed file can be returned directly to the user or stored in a document management system. IronPDF handles the entire pipeline, from HTML-to-PDF rendering to cryptographic signing, so you can implement the workflow without touching low-level PDF specification details.

How Do You Install IronPDF in an ASP.NET Core Project?

The fastest path to a working signing environment is the NuGet package. Open the Package Manager Console in Visual Studio and run:

Install-Package IronPdf
dotnet add package IronPdf
Install-Package IronPdf
dotnet add package IronPdf
SHELL

Alternatively, right-click the project in Solution Explorer, choose "Manage NuGet Packages," search for IronPdf, and click Install. After installation, add the following using directives at the top of your controller or service class:

using IronPdf;
using IronPdf.Signing;
using IronPdf;
using IronPdf.Signing;
$vbLabelText   $csharpLabel

IronPDF targets .NET 8 and .NET 9/10, so it fits naturally into modern ASP.NET Core projects. For a detailed walkthrough of the first-time setup, see the IronPDF quickstart guide.

How Do You Sign a PDF with a Certificate File in ASP.NET Core?

The most common signing approach uses a .pfx or .p12 certificate file. These files bundle the private key and the public certificate chain into a single password-protected archive. You can obtain one from a trusted certificate authority (CA) such as DigiCert or GlobalSign, or generate a self-signed certificate for development and testing.

The example below generates a PDF from HTML and applies a certificate-based digital signature:

using IronPdf;
using IronPdf.Signing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-certificate", (IWebHostEnvironment env) =>
{
    // Generate a PDF from HTML content
    var renderer = new ChromePdfRenderer();
    var document = renderer.RenderHtmlAsPdf("<h1>Contract Agreement</h1><p>Terms and conditions...</p>");

    // Locate the PFX certificate on the server
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");

    // Build the signature object
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningContact = "legal@yourcompany.com",
        SigningLocation = "Chicago, IL, USA",
        SigningReason = "Document Approval"
    };

    // Apply the signature and save
    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-contract.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-contract.pdf");
});

app.Run();
using IronPdf;
using IronPdf.Signing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-certificate", (IWebHostEnvironment env) =>
{
    // Generate a PDF from HTML content
    var renderer = new ChromePdfRenderer();
    var document = renderer.RenderHtmlAsPdf("<h1>Contract Agreement</h1><p>Terms and conditions...</p>");

    // Locate the PFX certificate on the server
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");

    // Build the signature object
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningContact = "legal@yourcompany.com",
        SigningLocation = "Chicago, IL, USA",
        SigningReason = "Document Approval"
    };

    // Apply the signature and save
    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-contract.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-contract.pdf");
});

app.Run();
$vbLabelText   $csharpLabel

ChromePdfRenderer converts any valid HTML string or URL into a PDF. The PdfSignature constructor accepts the certificate path and password, and the optional properties (SigningContact, SigningLocation, SigningReason) add metadata that PDF viewers display in the signature panel. The Sign method embeds the cryptographic signature, and SaveAs writes the signed file to disk.

Returning the Signed File from Memory

When you do not want to write a temporary file to disk, save the PDF to a MemoryStream and return it directly from the controller action:

var stream = new MemoryStream();
document.SaveAs(stream);
stream.Position = 0;
return Results.File(stream, "application/pdf", "signed-contract.pdf");
var stream = new MemoryStream();
document.SaveAs(stream);
stream.Position = 0;
return Results.File(stream, "application/pdf", "signed-contract.pdf");
$vbLabelText   $csharpLabel

This approach suits high-throughput APIs where temporary file management would add unnecessary overhead.

For a full property reference, see the PdfSignature API documentation.

How Do You Add a Visible Signature Image to a PDF?

Cryptographic signatures protect document integrity but are invisible in the rendered PDF. Many workflows -- particularly those involving contracts or letters -- also require a visible representation, such as a scanned handwritten signature or a company stamp, printed on the page.

IronPDF supports this through the LoadSignatureImageFromFile method. The method accepts an image path, a page index, and an IronSoftware.Drawing.Rectangle that defines the position and dimensions of the visible signature:

using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-visible-image", (IWebHostEnvironment env) =>
{
    // Load an existing PDF (for example, an invoice template)
    string pdfPath = Path.Combine(env.ContentRootPath, "Documents", "invoice.pdf");
    var document = PdfDocument.FromFile(pdfPath);

    // Paths to the certificate and the signature image
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    string imagePath = Path.Combine(env.ContentRootPath, "Images", "signature.png");

    // Define where the visible signature appears (x, y, width, height in points)
    var signatureArea = new Rectangle(50, 680, 200, 80);

    var signature = new PdfSignature(certPath, "yourPassword");
    signature.LoadSignatureImageFromFile(imagePath, pageIndex: 0, signatureArea);

    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-invoice.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-invoice.pdf");
});

app.Run();
using IronPdf;
using IronPdf.Signing;
using IronSoftware.Drawing;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/sign-with-visible-image", (IWebHostEnvironment env) =>
{
    // Load an existing PDF (for example, an invoice template)
    string pdfPath = Path.Combine(env.ContentRootPath, "Documents", "invoice.pdf");
    var document = PdfDocument.FromFile(pdfPath);

    // Paths to the certificate and the signature image
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    string imagePath = Path.Combine(env.ContentRootPath, "Images", "signature.png");

    // Define where the visible signature appears (x, y, width, height in points)
    var signatureArea = new Rectangle(50, 680, 200, 80);

    var signature = new PdfSignature(certPath, "yourPassword");
    signature.LoadSignatureImageFromFile(imagePath, pageIndex: 0, signatureArea);

    document.Sign(signature);
    string outputPath = Path.Combine(Path.GetTempPath(), "signed-invoice.pdf");
    document.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "signed-invoice.pdf");
});

app.Run();
$vbLabelText   $csharpLabel

The visible signature image is composited onto the specified page at the coordinates you provide. The cryptographic signature is applied to the entire document simultaneously, so you get both security and visual confirmation in a single operation.

If the image lives in memory (fetched from a database or cloud storage, for example), use LoadSignatureImageFromStream instead. For a deeper look at visual signing options, see the PDF signing how-to guide.

How Do You Create Signature Form Fields for External Signers?

In some workflows the document is created by your system but must be signed by an external party -- a customer, a partner, or a regulatory body. Rather than collecting a certificate from that party up front, you embed a dedicated signature form field in the PDF and send the document to them. Recipients open the PDF in Adobe Acrobat Reader or another compatible viewer, click the signature field, and apply their own certificate or electronic signature.

using IronPdf;
using IronPdf.Forms;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/generate-signable-form", (IWebHostEnvironment env) =>
{
    // Render the document that requires a client signature
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(@"
        <h1>Client Service Agreement</h1>
        <p>Please review the terms below and sign in the field provided.</p>
        <p>By signing, you confirm acceptance of all listed terms and conditions.</p>
    ");

    // Define the signature field: name, page, x, y, width, height (in points)
    var signatureField = new SignatureFormField(
        "ClientSignature",
        pageIndex: 0,
        x: 50,
        y: 600,
        width: 300,
        height: 100
    );

    pdf.Form.Add(signatureField);

    string outputPath = Path.Combine(Path.GetTempPath(), "client-agreement.pdf");
    pdf.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "client-agreement.pdf");
});

app.Run();
using IronPdf;
using IronPdf.Forms;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/generate-signable-form", (IWebHostEnvironment env) =>
{
    // Render the document that requires a client signature
    var renderer = new ChromePdfRenderer();
    var pdf = renderer.RenderHtmlAsPdf(@"
        <h1>Client Service Agreement</h1>
        <p>Please review the terms below and sign in the field provided.</p>
        <p>By signing, you confirm acceptance of all listed terms and conditions.</p>
    ");

    // Define the signature field: name, page, x, y, width, height (in points)
    var signatureField = new SignatureFormField(
        "ClientSignature",
        pageIndex: 0,
        x: 50,
        y: 600,
        width: 300,
        height: 100
    );

    pdf.Form.Add(signatureField);

    string outputPath = Path.Combine(Path.GetTempPath(), "client-agreement.pdf");
    pdf.SaveAs(outputPath);

    return Results.File(outputPath, "application/pdf", "client-agreement.pdf");
});

app.Run();
$vbLabelText   $csharpLabel

The SignatureFormField constructor parameters map directly to the field's position on the page. When the recipient opens the PDF, they see a clearly demarcated box where their signature should go. The completed form can then be returned to your system, where you can load it, validate the embedded signature, and archive it.

For more on PDF form handling -- including reading back submitted form data -- see the PDF form editing guide.

How Do You Verify a Digital Signature Programmatically?

After a document has been signed and returned, you may need to verify that the signature is still valid and that the document has not been altered. IronPDF exposes signature verification through the PdfDocument object:

using IronPdf;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/verify-signature", (IWebHostEnvironment env) =>
{
    string signedPath = Path.Combine(env.ContentRootPath, "Documents", "signed-contract.pdf");
    var document = PdfDocument.FromFile(signedPath);

    // Retrieve all embedded signatures
    var signatures = document.GetSignatures();

    foreach (var sig in signatures)
    {
        bool isValid = sig.VerifySignature();
        string status = isValid
            ? $"Valid -- signed by {sig.SignerName} on {sig.SigningTime:D}"
            : "INVALID -- document may have been tampered with";

        Console.WriteLine(status);
    }

    return Results.Ok(new { SignatureCount = signatures.Count });
});

app.Run();
using IronPdf;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/verify-signature", (IWebHostEnvironment env) =>
{
    string signedPath = Path.Combine(env.ContentRootPath, "Documents", "signed-contract.pdf");
    var document = PdfDocument.FromFile(signedPath);

    // Retrieve all embedded signatures
    var signatures = document.GetSignatures();

    foreach (var sig in signatures)
    {
        bool isValid = sig.VerifySignature();
        string status = isValid
            ? $"Valid -- signed by {sig.SignerName} on {sig.SigningTime:D}"
            : "INVALID -- document may have been tampered with";

        Console.WriteLine(status);
    }

    return Results.Ok(new { SignatureCount = signatures.Count });
});

app.Run();
$vbLabelText   $csharpLabel

GetSignatures() returns a list of all digital signatures embedded in the PDF. Each PdfDigitalSignature object exposes VerifySignature(), the signer's name, the signing timestamp, and the certificate chain. This information is enough to build an audit trail or a document management dashboard that flags any PDFs with broken or expired signatures.

How Do You Handle Certificate Management in Production?

Storing a .pfx file on the file system works during development but is not suitable for production. Certificate files contain private keys, and if the file is compromised, every document signed with that key is at risk.

Using Azure Key Vault

Azure Key Vault lets you store and use certificates without the private key ever leaving the vault. The .NET SDK provides a CertificateClient that downloads the public certificate information. For actual signing operations that keep the private key inside Key Vault, you can use the Azure.Security.KeyVault.Keys package to perform the cryptographic operation server-side.

Using Environment Variables and Secrets

For smaller projects, store the certificate as a Base64-encoded string in an environment variable or in ASP.NET Core Secrets Manager and decode it at runtime:

string certBase64 = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT environment variable is not set.");

byte[] certBytes = Convert.FromBase64String(certBase64);
string certPassword = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT_PASSWORD")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT_PASSWORD environment variable is not set.");

var signature = new PdfSignature(certBytes, certPassword);
string certBase64 = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT environment variable is not set.");

byte[] certBytes = Convert.FromBase64String(certBase64);
string certPassword = Environment.GetEnvironmentVariable("PDF_SIGNING_CERT_PASSWORD")
    ?? throw new InvalidOperationException("PDF_SIGNING_CERT_PASSWORD environment variable is not set.");

var signature = new PdfSignature(certBytes, certPassword);
$vbLabelText   $csharpLabel

This pattern keeps credentials out of source control and makes rotation straightforward -- update the environment variable and restart the service.

How Do You Batch-Sign Multiple PDFs Efficiently?

When you need to sign dozens or hundreds of documents in one operation -- for example, signing an entire batch of invoices at month-end -- loading the certificate once and reusing the PdfSignature object across all documents reduces overhead:

using IronPdf;
using IronPdf.Signing;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/batch-sign", (IWebHostEnvironment env) =>
{
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningReason = "Batch Invoice Approval"
    };

    string[] invoicePaths = Directory.GetFiles(
        Path.Combine(env.ContentRootPath, "Invoices"),
        "*.pdf"
    );

    string outputDir = Path.Combine(env.ContentRootPath, "Signed");
    Directory.CreateDirectory(outputDir);

    foreach (string invoicePath in invoicePaths)
    {
        var doc = PdfDocument.FromFile(invoicePath);
        doc.Sign(signature);
        string outputFile = Path.Combine(outputDir, Path.GetFileName(invoicePath));
        doc.SaveAs(outputFile);
    }

    return Results.Ok(new { SignedCount = invoicePaths.Length });
});

app.Run();
using IronPdf;
using IronPdf.Signing;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapPost("/batch-sign", (IWebHostEnvironment env) =>
{
    string certPath = Path.Combine(env.ContentRootPath, "Certificates", "certificate.pfx");
    var signature = new PdfSignature(certPath, "yourPassword")
    {
        SigningReason = "Batch Invoice Approval"
    };

    string[] invoicePaths = Directory.GetFiles(
        Path.Combine(env.ContentRootPath, "Invoices"),
        "*.pdf"
    );

    string outputDir = Path.Combine(env.ContentRootPath, "Signed");
    Directory.CreateDirectory(outputDir);

    foreach (string invoicePath in invoicePaths)
    {
        var doc = PdfDocument.FromFile(invoicePath);
        doc.Sign(signature);
        string outputFile = Path.Combine(outputDir, Path.GetFileName(invoicePath));
        doc.SaveAs(outputFile);
    }

    return Results.Ok(new { SignedCount = invoicePaths.Length });
});

app.Run();
$vbLabelText   $csharpLabel

Creating the PdfSignature object once outside the loop means the certificate file is read and parsed only once. Each iteration loads, signs, and saves an individual PDF. For very large batches, consider processing documents in parallel using Parallel.ForEach -- IronPDF's signing operations are thread-safe when each PdfDocument instance is isolated to a single thread.

How Do You Troubleshoot Common Signing Errors?

"Certificate not found" or "Invalid password"

Double-check the certificate path using File.Exists(certPath) before passing it to PdfSignature. Certificate passwords are case-sensitive and must match exactly. In development, it is common to generate a self-signed certificate with a simple password; in production, treat the password as a secret and load it from a secrets manager.

"Signature is invalid" in PDF Viewer

An "invalid signature" warning in Adobe Acrobat usually means one of three things: (1) the certificate is not trusted by the viewer's certificate store, (2) the document was modified after signing, or (3) the signing certificate has expired. For production use, obtain a certificate from a trusted CA and ensure the system clock is synchronized. For development, Adobe provides instructions for trusting self-signed certificates temporarily.

"Document is not signed" after calling Sign()

Calling document.Sign(signature) marks the document for signing, but the signature is finalized only when you call SaveAs or save to a stream. Ensure you are calling the save method after Sign, and verify the output file path is writable.

For full API details and troubleshooting resources, visit the IronPDF documentation hub and the IronPDF object reference. If you need support, the IronPDF support page connects you with the engineering team.

What Are Your Next Steps?

Digital PDF signing in ASP.NET Core becomes straightforward once you understand the three core operations: loading a certificate, calling Sign, and saving the result. IronPDF handles the cryptographic heavy lifting so you can focus on your application's business logic.

To continue building your document workflow, explore these related topics:

Start with a free IronPDF trial and have your first signed PDF running in under an hour. If you have questions or run into edge cases, the Iron Software support team is available to help you ship a reliable, legally compliant document signing workflow.

Frequently Asked Questions

What is a digital signature in ASP.NET Core?

A digital signature in ASP.NET Core is like a digital wax seal used to verify the authenticity and integrity of PDF documents. It ensures that the documents are legally valid and have not been tampered with.

How can I add a digital signature to a PDF document using IronPDF?

You can add a digital signature to a PDF document using IronPDF by including a certificate and setting it up to sign the document, ensuring it's both secure and verifiable.

Why are digital signatures important for my business documents?

Digital signatures are crucial because they verify that documents such as contracts or invoices are authentic and unchanged, thereby protecting your business from potential legal risks.

Can I create interactive form fields in PDFs with IronPDF?

Yes, IronPDF allows you to create interactive form fields in PDFs, which can enhance user interaction and streamline document processes in ASP.NET Core applications.

Is it possible to add visible signatures to my PDF documents?

Yes, with IronPDF, you can add visible signatures to your PDF documents, making it clear to recipients that the document is securely signed and verified.

What types of certificates can be used for digital signatures in PDFs?

You can use various types of certificates for digital signatures in PDFs, including self-signed certificates and those issued by a trusted Certificate Authority, depending on the level of security and trust required.

How does IronPDF ensure that a PDF document hasn't been tampered with?

IronPDF ensures that a PDF document hasn't been tampered with by using digital signatures that validate the document's integrity and authenticity, alerting recipients if changes have been made after signing.

Can I automate the digital signing process in ASP.NET Core applications?

Yes, you can automate the digital signing process in ASP.NET Core applications using IronPDF, which allows for batch processing and integration into existing workflows.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More

Iron Support Team

We're online 24 hours, 5 days a week.
Chat
Email
Call Me