👀 Live Preview
Modern secure forms use standard inputs and JavaScript APIs—not <keygen>:
keygen.
By the end of this tutorial, you’ll understand the historical <keygen> element and what to use instead for modern web security.
How <keygen> generated RSA key pairs inside forms.
Understand legacy name, challenge, and keytype.
Why <keygen> was removed from the HTML Living Standard.
Compare the legacy tag with the JavaScript Web Crypto API.
Use crypto.subtle, HTTPS, and WebAuthn for real auth.
Never rely on obsolete HTML for encryption or login.
<keygen> Tag?The <keygen> element was a specialized form control that generated a public/private key pair in the browser. When the form was submitted, the public key was sent to the server while the private key stayed on the client machine.
Do not use <keygen> in new projects. It was removed from the HTML Living Standard. Modern browsers no longer support it. Use the Web Crypto API, TLS/HTTPS, and standards like WebAuthn for authentication.
In the late 2000s and early 2010s, some developers experimented with <keygen> for certificate-based login. Poor cross-browser support, low adoption, and security concerns led browsers and the HTML spec to drop the element entirely.
// Modern replacement (simplified)
const keyPair = await crypto.subtle.generateKey(
{ name: "RSA-OAEP", modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
true, ["encrypt", "decrypt"]
);Legacy HTML placed <keygen> inside a <form> with a required name attribute:
<form>
<label for="keypair">Generate Key Pair:</label>
<keygen name="keypair" id="keypair">
</form><keygen> was a void element — no closing tag or inner content.<form> to submit the generated public key.name attribute was required for the key to appear in form data.| Topic | Legacy (keygen) | Modern replacement |
|---|---|---|
| Key generation | <keygen name="key"> | crypto.subtle.generateKey() |
| Challenge string | challenge attribute | Server-issued nonce + Web Crypto |
| Key algorithm | keytype="rsa" | Algorithm object in Web Crypto |
| Form binding | name on keygen | JavaScript + fetch or hidden input |
| Transport security | Not built in | HTTPS (TLS) |
| User login | Obsolete experiment | WebAuthn, OAuth, passkeys |
<keygen> vs Web Crypto APIModern cryptography in the browser uses JavaScript APIs instead of HTML form controls:
| Feature | <keygen> | Web Crypto API |
|---|---|---|
| Status | Obsolete, removed from HTML | Standard, supported in modern browsers |
| Key types | RSA only (keytype="rsa") | RSA, ECDSA, AES, and more |
| Browser support | Removed from Chrome & Firefox | Chrome, Firefox, Safari, Edge |
| Control | Automatic on form submit | Full programmatic control in JS |
| Security model | Inconsistent, deprecated | Actively maintained web platform API |
<!-- Legacy (do not use) -->
<form action="/register" method="post">
<keygen name="keypair" challenge="server-nonce">
<button type="submit">Register</button>
</form>
<!-- Modern: generate keys in JavaScript, send public key via fetch -->
<button type="button" id="register">Register</button>
<script>
document.getElementById("register").addEventListener("click", async () => {
const keys = await crypto.subtle.generateKey(/* ... */);
// Export public key and POST to server over HTTPS
});
</script>Browsers that once supported <keygen> recognized these attributes:
name RequiredIdentified the generated public key in submitted form data.
name="keypair"challenge ObsoleteBase64-encoded challenge string from the server to bind the key to a session.
challenge="randomstring"keytype ObsoleteKey algorithm type. Only rsa was supported in practice.
keytype="rsa"form ObsoleteAssociated the control with a form by id when placed outside it.
form="my-form"<keygen
name="keypair"
id="keypair"
challenge="randomstring"
keytype="rsa"
>All keygen attributes are historical only. The entire element is obsolete and ignored by modern browsers.
Historical keygen patterns plus the modern Web Crypto approach. Legacy examples are for learning only—they will not work in current browsers.
Modern secure forms use standard inputs and JavaScript APIs—not <keygen>:
keygen.How <keygen> looked inside a form. For learning only—modern browsers ignore it.
<form>
<label for="keypair">Generate Key Pair:</label>
<keygen name="keypair" id="keypair" challenge="randomstring">
</form>Developers once experimented with <keygen> for certificate-based login and client-side encryption. These use cases are now handled by Web Crypto, TLS, WebAuthn, and established authentication services.
A historical pattern for generating a client key pair during registration or login.
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<label for="keypair">Key Pair:</label>
<keygen name="keypair" id="keypair">
<input type="submit" value="Login">
</form>Another historical pattern that paired user data with a generated key on submit.
<form action="/submit" method="post">
<label for="data">Sensitive Data:</label>
<input type="text" id="data" name="data">
<label for="keypair">Encryption Key:</label>
<keygen name="keypair" id="keypair">
<input type="submit" value="Submit">
</form>This is what developers use today. Generate keys in JavaScript and send the public key over HTTPS.
<button type="button" id="genKey">Generate Key Pair</button>
<p id="status"></p>
<script>
document.getElementById("genKey").addEventListener("click", async () => {
const keys = await crypto.subtle.generateKey(
{ name: "RSA-OAEP", modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
true, ["encrypt", "decrypt"]
);
document.getElementById("status").textContent =
"Key pair generated successfully.";
});
</script>Since <keygen> is obsolete, style the modern form controls you actually use for login and registration:
label Clear field labels:focus Visible focus ringsautocomplete Password manager supportbutton Primary submit styling/* Modern login form styling */
form.auth-form {
display: flex;
flex-direction: column;
gap: 0.75rem;
max-width: 360px;
}
form.auth-form input {
padding: 0.5rem 0.75rem;
border: 1px solid #cbd5e1;
border-radius: 8px;
}
form.auth-form input:focus {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
form.auth-form button {
padding: 0.55rem 1rem;
border: none;
border-radius: 8px;
background: #2563eb;
color: #fff;
}Live styled auth form
Modern authentication must work for all users and follow current security standards:
<label>; do not rely on placeholder text alone.autocomplete values on login fields.Place keygen with a name inside form.
Supporting browsers created public and private keys when the form loaded or submitted.
On submit, only the public key was sent; the private key stayed on the client.
Learn keygen for history. Generate keys with crypto.subtle and authenticate with modern APIs.
<keygen> is obsolete and removed from the HTML Living Standard. Chrome and Firefox dropped it years ago; modern browsers do not support it.
Chrome removed keygen in version 57, Firefox in version 56. Safari, Edge, and Opera never offered reliable support. Do not use this tag in new documents.
Use these web platform APIs instead of keygen.
crypto.subtle.generateKey() for key pairsBottom line: Do not use <keygen> in new projects. Use the Web Crypto API, HTTPS, and modern authentication standards.
The <keygen> tag is a piece of web history—useful to recognize in old tutorials, but not for new sites. Beginners should learn the Web Crypto API, always deploy over HTTPS, and use established authentication patterns instead of obsolete HTML form controls.
crypto.subtle for browser key generationautocomplete on login fieldskeygen only to read legacy HTML<keygen> in any new HTML code<keygen>Bookmark these before you ship — they’ll keep your security approach modern and safe.
<keygen> was removed from the HTML Living Standard.
It generated RSA public/private keys on form submit.
BehaviorThe name attribute submitted the public key with the form.
crypto.subtle.generateKey() is the modern replacement.
Transport security requires TLS, not HTML tags.
SecurityChrome 57+ and Firefox 56+ do not support keygen.
Compatibilityname (required), challenge, keytype, autofocus, disabled, and form. All are obsolete.Skip deprecated keygen. Practice Web Crypto key generation in the Try It editor.
6 people found this page helpful