PEM to JWK Converter
Paste a PEM key or certificate, get a JWK with alg, use and kid stamped — and back again, entirely on this device.
Auto reads the algorithm off the key itself. HS256/HS384/HS512 are not offered here: an HMAC key is raw bytes and has no PEM form. Algorithm, use and kid are all stamped on the JWK — except Keep the pasted kid, which has nothing to keep when the source is a PEM, so it behaves as None.
The JWK members appear here as you paste.
This output contains private key material. It is hidden until you press Reveal, it is never stored, and it never leaves this browser.
Certificates: RSA and EC. A certificate gives up its public key here and nothing else — no subject, no SAN, no issuer, no validity, no trust decision.
A shared link carries the four settings above and nothing else — the key you pasted cannot travel in it.
What you paste is never stored — not in this browser, not anywhere else. Only the four settings above are remembered on this device.
Keyboard: s to swap direction · Ctrl ↵ to copy the output
This paste looks like key material. It is not stored anywhere, and it cannot travel in a shared link — there is no field in the link for it.
Do it offline:$ openssl pkcs8 -topk8 -nocrypt -in key.pem -out key.pk8.pem
How to use it
- Paste the key. The badge names the detected direction — a PEM fence reads one way, a JSON object with kty the other — and clicking it pins your choice.
- Leave Algorithm on Auto to have it read off the key itself, or pick one of the ten PEM-capable algorithms. Choose whether use is stamped sig, enc or left off.
- Choose where kid comes from: an RFC 7638 thumbprint computed here, the kid the pasted JWK already carried, or none at all.
- Read the chips — source format, curve or modulus size, kid provenance — then copy or download the result. Private members stay masked until you reveal them one at a time.
JOSE libraries want a JWK; openssl and your key files speak PEM. This page moves one key between the two spellings and stamps the members a JWK usually needs: alg, use and kid. Paste an SPKI public key, a PKCS#8 private key or an X.509 certificate — or paste a JWK to get the PEM back. Your browser reads the key; it is sent nowhere.
Examples
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFm+m9FXY2qiUUPR0Uzp
dIYpvgBPqLrEEE+PGr5Nx6DGApG531G4GDohJ+ZTrC1T9r0eU9dxyyceyAxJcdan
KjgsH+fdHRMlsEVnP2ouwm09fh2qzQGo4ynsdtaw562rhkyNyYIptVbHKDj4KUbN
+mQBTUebG6TDZmXIo00jvmsbZ8bvp94ylR5PLRecQL0PdxXF5fzX3xha2+l8w4Fc
4JNyyVZwrQ/45Mhne7dcpSbeQcRo+seD5OE4qEov/MILEymM3DSJluEd6HxtfzRR
Fndk5XQ5IJTRNm4TDyxXXv4qOsFapolMbqKVmM7jxadlBkfuV3PRu2n0H3gfT+cw
UQIDAQAB
-----END PUBLIC KEY-----
{
"kty": "RSA",
"n": "nFm-m9FXY2qiUUPR0UzpdIYpvgBPqLrEEE-PGr5Nx6DGApG531G4GDohJ-ZTrC1T9r0eU9dxyyceyAxJcdanKjgsH-fdHRMlsEVnP2ouwm09fh2qzQGo4ynsdtaw562rhkyNyYIptVbHKDj4KUbN-mQBTUebG6TDZmXIo00jvmsbZ8bvp94ylR5PLRecQL0PdxXF5fzX3xha2-l8w4Fc4JNyyVZwrQ_45Mhne7dcpSbeQcRo-seD5OE4qEov_MILEymM3DSJluEd6HxtfzRRFndk5XQ5IJTRNm4TDyxXXv4qOsFapolMbqKVmM7jxadlBkfuV3PRu2n0H3gfT-cwUQ",
"e": "AQAB",
"alg": "RS256",
"use": "sig",
"kid": "m3IflMgIeGbvWenW2I2LOKntvBLUC6DCqHCIMAdc_pY"
}The everyday case: a 2048-bit SPKI public key becoming the shape a JWKS entry wants. Auto reads RS256 off the key, the modulus arrives as the base64url member n, and kid is a thumbprint of {e, kty, n}.
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPy/QEEL4hR+utiGu
64HVWqa1QdlfKM0jZ7EWhRuRPvWhRANCAASH+KbD6PZYRrQmxfbYSeQnEbHFnlhq
QdrOFG/hoBqG0BAZCO0hU0zafJbBGLr7YARsewqW7Db1oJvY430/Zl1X
-----END PRIVATE KEY-----
{
"kty": "EC",
"crv": "P-256",
"x": "h_imw-j2WEa0JsX22EnkJxGxxZ5YakHazhRv4aAahtA",
"y": "EBkI7SFTTNp8lsEYuvtgBGx7CpbsNvWgm9jjfT9mXVc",
"d": "Py_QEEL4hR-utiGu64HVWqa1QdlfKM0jZ7EWhRuRPvU",
"alg": "ES256",
"use": "sig",
"kid": "S--m65SW0DCLEZecZ6DONw500wmOo5tv9nYkxw5qgAM"
}A PKCS#8 P-256 signing key — a throwaway fixture, printed in full. On the page the private member d stays masked until you reveal it. The kid ignores d: RFC 7638 digests public members only, so a pair and its public half share one.
-----BEGIN CERTIFICATE-----
MIIBODCB4AIJAPB5lpF2yzcrMAoGCCqGSM49BAMCMCUxIzAhBgNVBAMMGnBlbS10
by1qd2suZml4dHVyZS5pbnZhbGlkMB4XDTI2MDgxNzIxMDM1OVoXDTM2MDgxNDIx
MDM1OVowJTEjMCEGA1UEAwwacGVtLXRvLWp3ay5maXh0dXJlLmludmFsaWQwWTAT
BgcqhkjOPQIBBggqhkjOPQMBBwNCAASH+KbD6PZYRrQmxfbYSeQnEbHFnlhqQdrO
FG/hoBqG0BAZCO0hU0zafJbBGLr7YARsewqW7Db1oJvY430/Zl1XMAoGCCqGSM49
BAMCA0cAMEQCIEnQyQAGc2SY6YC7Td2W4LtGXy/MLzu7vZ6vq9WOdjpDAiBYmLql
fiEKr6JwVm8ZG2Brv28lY7ktdH8Juka8qdabNA==
-----END CERTIFICATE-----
{
"kty": "EC",
"crv": "P-256",
"x": "h_imw-j2WEa0JsX22EnkJxGxxZ5YakHazhRv4aAahtA",
"y": "EBkI7SFTTNp8lsEYuvtgBGx7CpbsNvWgm9jjfT9mXVc",
"alg": "ES256",
"use": "sig",
"kid": "S--m65SW0DCLEZecZ6DONw500wmOo5tv9nYkxw5qgAM"
}The certificate carrying the previous example's key. Only subjectPublicKeyInfo is walked out of the DER, so you get the public half and its identical thumbprint — no validity dates.
{
"kty": "EC",
"crv": "P-256",
"x": "h_imw-j2WEa0JsX22EnkJxGxxZ5YakHazhRv4aAahtA",
"y": "EBkI7SFTTNp8lsEYuvtgBGx7CpbsNvWgm9jjfT9mXVc",
"alg": "ES256",
"use": "sig",
"kid": "S--m65SW0DCLEZecZ6DONw500wmOo5tv9nYkxw5qgAM"
}-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEh/imw+j2WEa0JsX22EnkJxGxxZ5Y
akHazhRv4aAahtAQGQjtIVNM2nyWwRi6+2AEbHsKluw29aCb2ON9P2ZdVw==
-----END PUBLIC KEY-----
The reverse direction, fed the previous example's output: the JWK returns as the SPKI file openssl would have written. Body lines wrap at 64 columns with a trailing newline, so diffs stay quiet.
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAnFm+m9FXY2qiUUPR0UzpdIYpvgBPqLrEEE+PGr5Nx6DGApG5
31G4GDohJ+ZTrC1T9r0eU9dxyyceyAxJcdanKjgsH+fdHRMlsEVnP2ouwm09fh2q
zQGo4ynsdtaw562rhkyNyYIptVbHKDj4KUbN+mQBTUebG6TDZmXIo00jvmsbZ8bv
p94ylR5PLRecQL0PdxXF5fzX3xha2+l8w4Fc4JNyyVZwrQ/45Mhne7dcpSbeQcRo
+seD5OE4qEov/MILEymM3DSJluEd6HxtfzRRFndk5XQ5IJTRNm4TDyxXXv4qOsFa
polMbqKVmM7jxadlBkfuV3PRu2n0H3gfT+cwUQIDAQABAoIBAQCVbMfYTyf/oafj
lrduGt17OcWnCtEW5vf+xqpz2rCnOyZCylcj8QvKS7PoWB5bjS6Tv4a+hkcA6zBl
7Cg9HfLBTNIO5B/Ua7o3Tv0wBCEQPCrq3xufthhcknKl2OVVZgtp3Lwde8K0xmys
KlYxzLOKvAzqeKbqsnr04A3y1AR3NJOfukaqRdD5w5XAdi/I0+yXvCUhC1asKiy4
TehBMvzWaWC4u/+wXNeY9QIFFVlhCNddlC28VX+lO9YIArOt082ELfDZXZJ8iNjJ
cx/On4TY1vErQGcuSeLG+gqdjXN6R/Hel/3ySGvz2rPvNE64E0+H2bzOGKZnqG6i
ZWWE+IDpAoGBAMk+meW0pMqSeTYm8EoXmJB8gf9IbHKwOxdUhVFRg8N1hTNEmzyh
8SL6LpApIDZMTpICN6nWFljFhaZZrl0zw8HXCiTjkK1ikiK201CYxaZ6+KbHjwSt
uqT6nVVGl6SS51r63qwkN9TjaLMEjcGe+A12mbGoD/XU0sX6EI8eSdvfAoGBAMbk
Hk6OY+Axcxzh18QVjsZTt4Tv2KzTgL/o4ruY/GfZwv1Bd//MhKYaz79toljQjyap
CPoYdT/oPUWQ07zw1nqkNeG5hfNL+fHoFSAQjuBDYAf21M4cDSLi/xNv8/OMXxZw
WCWLbE+cRGgPe89iDD8dZXLoNou7f92PCwt+/nnPAoGBAJxSwIEqnYet1/I0tRsY
0S4LSX/f5j4AnyY0RYsxYsUGGP4GIQAsW3/sDxd0ms0S4UWR62NGJf23EWZy63sC
puGABSU6kDvfAd1tXyCQS5hSlawYAASGXyGge26uc0UnyAdoMGhPif8Y10+YDfWF
YvIyWpkiD6PKOiAHa62AvabJAoGAK5LSqPc9HmL3Cz7XXJg0fXLd4/wABm0X6fOF
qP/tXHsy4vUy6xHNhe6d0Ryd0sNueVPTKaeuGGAy/EisetpwwtGzFE7m79SXX84u
wqWeB7f7FAOZv8YZgqkkpQeD9LmuI2ZdiWwwQIjF2954i4i5kiJIlZIWUSq06r9p
9gzOh7UCgYBMPDlnQgqcEgq9Qdm6vtkP5/D6cbqsndbtKy2zlgKzTV4I9evIvTHA
ojnBEgL/bfSOq2zKhx09zDEYpduCtkpGE1xh7moukG1bFFeqsc37Rue7amssL2T9
U176aKtLdDAE7GDgzsDBsG2sSc11v14tJTyUDBsf4EN6MvUuczAtYw==
-----END RSA PRIVATE KEY-----
A `RSA PRIVATE KEY` block is PKCS#1 (RFC 8017 Appendix A.1): the RSA numbers with no algorithm wrapper around them. Web Crypto reads only the PKCS#8 `PRIVATE KEY` wrapper, so this browser cannot open it as it stands. Convert it once, then paste the result: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key.pk8.pemThe refusal you are likeliest to hit. Older openssl writes this fence by default and no browser has an importer for it, so the answer is one command run locally.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A certificate contributes exactly one thing
The DER is walked only as far as subjectPublicKeyInfo (RFC 5280 §4.1), and those bytes go straight to the importer. Subject, issuer, SAN, validity and key usage are stepped over unread. Certificate support is declared for RSA and EC keys; anything else is refused rather than half-converted.
Two fences the browser genuinely cannot open
BEGIN RSA PRIVATE KEY is PKCS#1 and BEGIN EC PRIVATE KEY is SEC1: raw numbers with no AlgorithmIdentifier wrapper. Web Crypto imports only spki and pkcs8, so neither is a bug to work around — the wrapper is missing, and the refusal prints the openssl line that adds it. ENCRYPTED PRIVATE KEY stops for another reason: this page never asks for a passphrase.
Extra blocks are declared, never dropped
Paste a key and its certificate together, or a two-cert chain, and the first importable block is converted while a chip records which one was used and how many were left alone. Text outside the fences is ignored per RFC 7468 §2; CRLF endings are fine.
What the shareable link can and cannot carry
Share encodes four values: direction, algorithm, use and kid source. That state has no field for the key, so no paste can travel in a URL even by accident, and nothing is written to this device unless you press Download. The JWK is equally spare — ext and key_ops are never added.
Common errors
A `RSA PRIVATE KEY` block is PKCS#1 (RFC 8017 Appendix A.1): the RSA numbers with no algorithm wrapper around them. Web Crypto reads only the PKCS#8 `PRIVATE KEY` wrapper, so this browser cannot open it as it stands. Convert it once, then paste the result: openssl pkcs8 -topk8 -nocrypt -in key.pem -out key.pk8.pem- The commonest stop. That command rewraps the same key rather than re-generating it. A PKCS#1 public key draws the same code with openssl rsa -pubout printed instead.
Nothing here is PEM: no matching BEGIN/END fence pair. A PEM block opens with a line like -----BEGIN PUBLIC KEY----- and closes with the identical -----END PUBLIC KEY----- line, with base64 in between (RFC 7468 section 2).- Usually a paste that took the base64 body but not the two fence lines. Adding the matching pair back is enough: the label between the dashes names the format.
The PUBLIC KEY block's body is not standard base64 — the character "_" (U+005F) at line 2, column 38 is not a base64 character. PEM bodies use the standard base64 alphabet A-Z a-z 0-9 + / with = padding (RFC 7468 section 3); base64url's - and _ are not PEM.- This catches bytes that already went through a base64url step — a JWK member pasted between PEM fences. A line and column locate it; nothing is silently translated back.
That is not valid JSON, so it cannot be a JWK: the top level is a JSON array — a key set is {"keys":[…]}, and a single key is the object inside it. A JWK is a JSON object, for example {"kty":"EC","crv":"P-256","x":"…","y":"…"}.- Raised by a bare array — the keys list copied without its wrapper. Paste one object from it; a whole key set draws the missing-kty message instead.
FAQ
Does the key I paste leave this device?
No. Conversion runs in the page through the browser's own Web Crypto, and the tool makes no network request of any kind — its files hold no fetch, XMLHttpRequest, sendBeacon or EventSource call, which the test suite checks by grep. Only your four option settings are remembered, never a paste.
Where does the alg value come from, and can I set it myself?
On Auto it is read off the key: RSA imports as RS256, P-256 as ES256, Ed25519 as EdDSA. That is a default, not a fact about the key — the same RSA key is equally valid as PS256 — so the picker offers the ten algorithms a PEM key can carry and refuses mismatches. HS256/HS384/HS512 are absent: an HMAC secret has no PEM form.
Why is the kid different from the one my JWKS already uses?
Because Thumbprint computes a fresh one: the RFC 7638 digest of the required members in lexicographic order, a property of the key rather than of your deployment. A PEM has no key id field: Preserve only leaves a pasted JWK's own kid alone, and the emitted PEM never carries one.
Keyboard shortcuts
- s
- Swap the direction (single-key; obeys the kill switch).
- ⌘/Ctrl + Enter
- Copy the output pane.