cyberangles blog

HTML `<keygen>` Tag: A Historical Perspective and Modern Alternatives

The HTML <keygen> tag was a specialized form element historically used to generate a public-private key pair for secure form submissions (e.g., client-side certificate authentication). However, it is now deprecated and unsupported in modern browsers due to security concerns, limited browser support, and the availability of more robust cryptographic alternatives. This blog explores its purpose, usage, deprecation, and modern replacements.

2026-06

Table of Contents#

What is the HTML <keygen> Tag?#

The <keygen> element was an HTML form control that generated a public-private key pair when a form was submitted. The public key was sent to the server, while the private key remained on the client (stored in the browser’s key store). It aimed to enable:

  • Secure client authentication (e.g., client-side TLS certificates).
  • Encryption/decryption of form data using client-generated keys.

How It Worked#

When a form with <keygen> was submitted, the browser:

  1. Generated an RSA key pair (by default, though keytype allowed other algorithms in theory).
  2. Sent the public key (or a certificate signing request, CSR) to the server via the form.
  3. Stored the private key in the browser’s key store (e.g., for later use in authentication).

Syntax and Attributes#

The <keygen> tag is a void element (no closing tag) and was used inside <form> elements. It supported the following attributes:

AttributeDescription
name(Required) Name of the control (used in form data submission).
challengeA string signed with the private key (used to verify key origin).
keytypeKey algorithm (only rsa was widely supported; others were non-standard).
disabledDisables the keygen control.
formAssociates the control with a form (if not a direct child of <form>).
autofocusAutomatically focuses the control on page load.

Example Usage#

Here’s a historical example of a form using <keygen> to generate an RSA key pair for client authentication:

<!DOCTYPE html>
<html>
  <body>
    <form action="submit_key.php" method="post">
      <label for="username">Username:</label>
      <input type="text" id="username" name="username" required>
      <!-- Generate an RSA key pair -->
      <keygen name="clientKey" keytype="rsa" challenge="random_challenge_123">
      <input type="submit" value="Submit Key">
    </form>
  </body>
</html>

When submitted, the browser generated an RSA key pair. The public key (in a signed format, e.g., a CSR) was sent to submit_key.php, while the private key remained in the browser.

Historical Common Practices#

The <keygen> tag was primarily used in:

  • Enterprise Client Authentication: Corporate intranets used it to generate client-side TLS certificates. The server would sign the client’s public key (via a CSR) and issue a certificate for secure access.
  • Secure Form Submissions: For encrypting sensitive data (e.g., financial forms) using client-generated keys.

Deprecation and Best Practices#

Why Deprecated?#

  1. Browser Support: Modern browsers (Chrome, Firefox, Safari, Edge) have deprecated or removed <keygen> due to low adoption and security risks.
  2. Security Issues:
    • Inconsistent key generation across browsers led to vulnerabilities.
    • Storing private keys in the browser’s key store exposed them to malicious scripts.
  3. Better Alternatives: Modern web standards (e.g., WebCrypto API) offer more secure, flexible key management.

Best Practices (Now)#

  • Avoid <keygen> entirely—it is not supported in modern browsers and poses security risks.
  • Use modern cryptographic methods (e.g., WebCrypto API, server-side key generation) for secure key management.

Alternatives to <keygen>#

1. WebCrypto API#

The WebCrypto API is a JavaScript API for secure cryptographic operations (key generation, signing, encryption). It is supported in all modern browsers.

Example: Generate an RSA Key Pair with WebCrypto#

async function generateRSAKeyPair() {
  const keyPair = await window.crypto.subtle.generateKey(
    {
      name: "RSA-OAEP",
      modulusLength: 2048, // Key length (2048+ bits recommended)
      publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // 65537
      hash: "SHA-256", // Hashing algorithm for OAEP
    },
    true, // Extractable (for signing/encryption)
    ["encrypt", "decrypt"] // Key usage
  );
  return keyPair;
}
 
// Usage:
generateRSAKeyPair().then((keyPair) => {
  console.log("Public Key:", keyPair.publicKey);
  console.log("Private Key:", keyPair.privateKey);
});

2. Server-Side Key Generation#

Generate keys on the server (e.g., using Node.js crypto or Python’s cryptography library) and transmit them securely to the client via TLS.

Example: Node.js Server-Side Key Generation#

const crypto = require('crypto');
 
// Generate an RSA key pair
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: { type: 'spki', format: 'pem' },
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
});
 
console.log("Public Key (PEM):", publicKey);
console.log("Private Key (PEM):", privateKey);

3. Cryptographic Libraries#

Use JavaScript libraries like Forge or SJCL for simpler cryptographic operations (though WebCrypto is preferred for native browser support).

Conclusion#

The <keygen> tag was a historical tool for client-side key generation but is now deprecated due to security issues and lack of browser support. Modern web development demands secure, standardized cryptographic methods like the WebCrypto API or server-side key generation. When building secure applications, prioritize these modern alternatives to ensure compatibility, security, and reliability.

References#