PEM to JWK converter

Client-side only. Encrypted PEM and PKCS#1 (BEGIN RSA PRIVATE KEY) are not imported, convert those to unencrypted PKCS#8 first.

By Cobra · Last updated

Which PEM shapes import

Paste an SPKI public key (BEGIN PUBLIC KEY) or PKCS#8 private key (BEGIN PRIVATE KEY). The browser Web Crypto import extracts the RSA or EC parameters and emits JWK JSON with kty, n/e or curve coordinates, and d only for private keys.

Encrypted PEM (BEGIN ENCRYPTED PRIVATE KEY) and legacy PKCS#1-only blocks may not import depending on browser support. Convert those with OpenSSL locally first if needed.

Worked example: RSA public and private keys

An SPKI RSA public PEM becomes a JWK with "kty":"RSA", modulus n, and exponent e (often AQAB). A matching private PKCS#8 adds private fields such as d. Pretty-printed JSON is easier to paste into JWKS documents; minify before embedding in configs if size matters.

Limits

Keys never leave this tab, but screen sharing still exposes them. Do not paste production private keys into a shared demo. This tool does not mint certificates, rotate keys, or talk to a KMS.

Worked example: RSA vs EC P-256 output

Paste a public key that begins with -----BEGIN PUBLIC KEY-----. For an RSA key the JWK has "kty":"RSA" with n (modulus) and e (usually AQAB, which is 65537). For an EC P-256 key it has "kty":"EC", "crv":"P-256", and the x and y coordinates. Add kid, use, and alg yourself if your JWKS consumer needs them.

Pitfalls

Convert PEM to JWK in code

Each snippet reads an SPKI public key PEM, exports it as a JWK and sets kid to the RFC 7638 thumbprint. All three print the same kid for the same key.

JavaScript: jose

import { importSPKI, exportJWK, calculateJwkThumbprint } from "jose"; // npm i jose
import { readFileSync } from "node:fs";

const pem = readFileSync("public.pem", "utf8"); // -----BEGIN PUBLIC KEY-----
const key = await importSPKI(pem, "RS256", { extractable: true });
const jwk = await exportJWK(key);
jwk.kid = await calculateJwkThumbprint(jwk); // RFC 7638 thumbprint as kid
console.log(JSON.stringify({ ...jwk, alg: "RS256", use: "sig" }));
// Private keys: importPKCS8(pem, "RS256", { extractable: true })

Python: jwcrypto

import json
from jwcrypto import jwk  # pip install jwcrypto

with open("public.pem", "rb") as f:
    key = jwk.JWK.from_pem(f.read())  # SPKI public or PKCS#8 private

public = key.export_public(as_dict=True)
public["kid"] = key.thumbprint()  # RFC 7638, SHA-256
print(json.dumps(public))

Go: github.com/lestrrat-go/jwx/v3

package main

import (
	"encoding/json"
	"fmt"
	"os"

	"github.com/lestrrat-go/jwx/v3/jwk" // go get github.com/lestrrat-go/jwx/v3
)

func main() {
	pem, err := os.ReadFile("public.pem")
	if err != nil {
		panic(err)
	}
	key, err := jwk.ParseKey(pem, jwk.WithPEM(true))
	if err != nil {
		panic(err)
	}
	if err := jwk.AssignKeyID(key); err != nil { // RFC 7638 thumbprint as kid
		panic(err)
	}
	out, _ := json.Marshal(key)
	fmt.Println(string(out))
}

Each snippet was run on October 14, 2026 with jose 6.2.12, jwcrypto 1.6.1 and jwx v3.3.0.

JWK and PEM specs

FAQ

Does PEM to JWK upload my key?

No. Import and export run in the browser with Web Crypto.

Public vs private PEM?

PUBLIC KEY (SPKI) yields a public JWK. PRIVATE KEY (PKCS#8) yields a private JWK. Do not publish private JWKs.

Why did import fail?

Encrypted PEMs, exotic curves, or truncated paste often fail. Confirm BEGIN/END lines and that the key type is RSA or EC supported by your browser.

Can I build a JWKS?

Wrap one or more public JWKs in {"keys":[...]}. This page converts a single PEM at a time.

What is a JWKS?

A JSON Web Key Set is a JSON object with a keys array of JWKs. Identity providers publish one so clients can verify token signatures. Wrap your JWK in a keys array object.

Is it safe to paste a private key here?

Conversion runs in your browser, but the safest habit is to only handle private keys on machines you trust and never paste them into shared screens or chats.