T
THINKFORU
Submit Feedback

JWKS viewer / JWK <-> PEM converter

JWKS Viewer & Converter: PEM to JWK & Thumbprint

JWKS viewer / JWK ↔ PEM converter

Save on Google

Free JWKS viewer and JWK to PEM converter. Inspect keys, check them for mistakes, and convert between JWK and PEM. Everything runs in your browser. Nothing is uploaded.

Configure keys

Results & Output

    Keys

      The tool runs in your browser. Do not share links or files that contain private keys.

      Passkeys, OAuth and Identity

      Tool What it does
      WebAuthn options JSON builder / inspector Build WebAuthn registration or sign-in options, or paste existing JSON to check it. It catches mistakes such as a padded challenge, a wrong rp.id, or an email used as the user ID, so your passkey setup works the first time.
      PKCE code verifier / challenge generator Create a PKCE code verifier and its S256 code challenge in your browser, check values you already have, and get the authorization and token requests ready to use. Handy when a login fails with invalid_grant.
      OIDC discovery document validator Paste the JSON from /.well-known/openid-configuration and see which required fields are missing, which URLs are wrong, and whether the issuer matches. The results are color-coded, so you spot problems fast.
      OAuth redirect URI and scope checker Compare the redirect URI in your request with the ones registered for your app, and check your scopes for mistakes. It helps you fix redirect_uri_mismatch and invalid_scope errors.

      What does a JWKS viewer and JWK to PEM converter do?

      A JSON Web Key Set lists the public keys that applications use to verify tokens, while servers and tools such as OpenSSL usually expect PEM files. This tool shows what is inside a JWKS (key type, size or curve, algorithm, thumbprint and whether a key is private), checks every key for common mistakes, and converts in both directions between JWK and PEM. RSA keys are checked for size, EC keys are checked to be on their curve, and any private data is flagged in red. It does not read certificates or encrypted keys.

      JWK and PEM 100+ developer references

      Click Copy to copy a snippet. Snippets are examples, so replace placeholders such as auth.example.com and file names with your own values. Library APIs change, so check the documentation of your version.

      Conceptwhat it meansFieldJWK memberFormatPEM and encodingErrorcommon problemSecuritysafety checkHow-topractical step
      Showing 105 of 105 questions
      Developer QuestionCopy-ready SnippetExplanation
      ConceptWhat is a JWK?{ "kty": "RSA", "n": "...", "e": "AQAB", "kid": "key-1" }A JSON Web Key (RFC 7517) is a JSON representation of a cryptographic key.
      ConceptWhat is a JWKS?{ "keys": [{ "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }] }A JWK Set is a JSON object with a keys array. Providers publish one so clients can verify tokens.
      How-toWhere do I find a provider’s JWKS?curl -s https://auth.example.com/.well-known/openid-configuration | jq -r .jwks_uriRead jwks_uri from the OpenID discovery document.
      FieldWhat is kty?"kty": "RSA"The key type: RSA, EC, OKP or oct.
      FieldWhat is kid?"kid": "2024-key-1"A key ID. A token header carries a kid so the verifier can pick the matching key.
      FieldWhat is use?"use": "sig"sig means signing and verification. enc means encryption.
      FieldWhat is alg in a JWK?"alg": "RS256"The algorithm the key is meant for.
      FieldWhat is key_ops?"key_ops": ["verify"]An optional list of allowed operations. Do not combine it with a conflicting use.
      ConceptWhat is a JWK thumbprint?{"e":"AQAB","kty":"RSA","n":"..."}RFC 7638 defines it as the SHA-256 hash of the required members in a fixed order, as base64url. It is a stable key ID.
      FormatWhat is PEM?-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----A text format: base64 of DER data between BEGIN and END lines.
      FormatPEM vs JWK// PEM: base64 DER text JWK: JSON membersBoth describe the same key. JWK is JSON for web protocols, and PEM is common in OpenSSL and servers.
      FormatWhat is SPKI?-----BEGIN PUBLIC KEY-----SubjectPublicKeyInfo is the standard public key container. Its PEM label is PUBLIC KEY.
      FormatWhat is PKCS#8?-----BEGIN PRIVATE KEY-----A standard container for private keys of any type. Its PEM label is PRIVATE KEY.
      FormatWhat is PKCS#1?-----BEGIN RSA PRIVATE KEY----- -----BEGIN RSA PUBLIC KEY-----The older RSA-only formats. Their labels contain the word RSA.
      FormatWhat is EC PRIVATE KEY (SEC1)?-----BEGIN EC PRIVATE KEY-----The older EC private key format that openssl ecparam produces.
      Formatbase64url vs base64btoa(str).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")JWK values use base64url without padding. PEM uses standard base64 with padding.
      FieldRSA modulus n"n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmb..."The RSA modulus as base64url.
      FieldRSA exponent e"e": "AQAB"The public exponent. AQAB is 65537, the usual value.
      SecurityRSA private exponent d"d": "..."Its presence means the JWK holds a private key.
      SecurityRSA p, q, dp, dq, qi"p", "q", "dp", "dq", "qi"More private key values. They are never part of a public key.
      FieldEC crv"crv": "P-256"The curve: P-256, P-384 or P-521.
      FieldEC x and y"x": "...", "y": "..."The public point coordinates as base64url, with the full length of the curve.
      SecurityEC private value d"d": "..."The EC private key value. Never publish it.
      FieldOKP Ed25519 public key{ "kty": "OKP", "crv": "Ed25519", "x": "..." }An Edwards-curve public key, used with the EdDSA algorithm.
      Securityoct (symmetric) key{ "kty": "oct", "k": "..." }A shared secret. Never publish a JWKS that contains k.
      FieldCoordinate size for P-256x and y: 32 bytes = 43 base64url charactersBoth coordinates must have the full length of the curve.
      FieldCoordinate size for P-384x and y: 48 bytes = 64 base64url charactersBoth coordinates must have the full length of the curve.
      FieldCoordinate size for P-521x and y: 66 bytes = 88 base64url charactersBoth coordinates must have the full length of the curve.
      FieldWhich alg fits which key?RS256, PS256 -> RSA ES256 -> P-256 ES384 -> P-384 ES512 -> P-521 EdDSA -> OKPA mismatch makes verification fail. The validator flags it.
      FieldRS256 vs PS256"alg": "PS256"Both use an RSA key. RS256 uses PKCS#1 v1.5 padding and PS256 uses PSS padding.
      ErrorES512 uses P-521"alg": "ES512", "crv": "P-521"Despite the 512 in the name, ES512 uses the P-521 curve.
      SecurityMinimum RSA key sizeopenssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048Use at least 2048 bits. The tool warns about smaller keys.
      How-toJWKS with several keys{ "keys": [{ "kid": "new-key", ... }, { "kid": "old-key", ... }] }List the new and the old key during a rotation, each with a unique kid.
      How-toGenerate an RSA private keyopenssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pemCreates a 2048-bit key in PKCS#8 format.
      How-toExtract the public key from a private keyopenssl pkey -in private.pem -pubout -out public.pemWrites a PUBLIC KEY PEM.
      How-toGenerate an EC P-256 key (SEC1)openssl ecparam -name prime256v1 -genkey -noout -out ec-private.pemCreates an EC PRIVATE KEY PEM.
      How-toGenerate an EC P-256 key (PKCS#8)openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ec-private.pemCreates a PRIVATE KEY PEM.
      How-toGenerate an Ed25519 keyopenssl genpkey -algorithm ED25519 -out ed25519-private.pemCreates a PKCS#8 private key.
      How-toConvert PKCS#1 to PKCS#8openssl pkcs8 -topk8 -nocrypt -in rsa-private.pem -out pkcs8-private.pemTurns RSA PRIVATE KEY into PRIVATE KEY.
      How-toConvert PKCS#8 to PKCS#1 (RSA)openssl rsa -in pkcs8-private.pem -traditional -out pkcs1-private.pemNeeds OpenSSL 3. Turns PRIVATE KEY into RSA PRIVATE KEY.
      How-toShow key detailsopenssl pkey -in key.pem -text -nooutPrints the key parameters in readable form.
      How-toGet the public key from a certificateopenssl x509 -in cert.pem -pubkey -nooutPrints a PUBLIC KEY PEM that you can paste into the tool.
      How-toShow the RSA modulus of a public keyopenssl rsa -pubin -in public.pem -modulus -nooutPrints the modulus in hex.
      How-toConvert DER to PEMopenssl pkey -inform DER -in key.der -out key.pemUse -pubin for a DER public key.
      How-toConvert PEM to DERopenssl pkey -in key.pem -outform DER -out key.derWrites the binary DER form.
      How-toDecrypt an encrypted private keyopenssl pkey -in encrypted.pem -out decrypted.pemIt asks for the passphrase. This tool never reads encrypted keys.
      How-toCertificate SHA-256 fingerprintopenssl x509 -in cert.pem -noout -fingerprint -sha256A fingerprint of the certificate, not the same as a JWK thumbprint.
      How-toCheck that a private and a public key matchdiff <(openssl pkey -in private.pem -pubout) public.pemNeeds a shell that supports process substitution, such as bash.
      How-toNode.js: JWK to a key objectconst key = crypto.createPublicKey({ key: jwk, format: "jwk" });Works for public and private JWKs.
      How-toNode.js: export a PEM from a keyconst pem = key.export({ type: "spki", format: "pem" });Use type "pkcs8" for a private key.
      How-toNode.js: PEM to JWKconst jwk = crypto.createPublicKey(pem).export({ format: "jwk" });Returns the JWK members as an object.
      How-toNode.js: export a private PEM (PKCS#8)const pem = privateKey.export({ type: "pkcs8", format: "pem" });Keep the result secret.
      How-toNode.js: generate an EC key pairconst { publicKey, privateKey } = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });Use "rsa" with modulusLength for RSA keys.
      How-toNode.js: JWK thumbprint of an RSA keycrypto.createHash("sha256").update(JSON.stringify({ e: jwk.e, kty: jwk.kty, n: jwk.n })).digest("base64url")The members must stay in this order. EC keys use crv, kty, x and y.
      How-tojose: import a JWKconst key = await importJWK(jwk, "RS256");Imports a JWK as a key you can verify with.
      How-tojose: export a PEMconst pem = await exportSPKI(publicKey);Use exportPKCS8 for a private key.
      How-tojose: PEM to JWKconst key = await importSPKI(pem, "RS256"); const jwk = await exportJWK(key);Imports the PEM public key, then exports it as a JWK.
      How-tojose: thumbprintconst kid = await calculateJwkThumbprint(jwk);Returns the RFC 7638 thumbprint.
      How-tojose: remote JWKSconst JWKS = createRemoteJWKSet(new URL("https://auth.example.com/.well-known/jwks.json"));Fetches and caches the key set.
      How-tojose: verify a token with a JWKSconst { payload } = await jwtVerify(token, JWKS, { issuer, audience });Checks the signature, issuer and audience.
      How-toBrowser: import an RSA JWKconst key = await crypto.subtle.importKey("jwk", jwk, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, true, ["verify"]);Use RSA-PSS for PS256 keys.
      How-toBrowser: import an EC JWKconst key = await crypto.subtle.importKey("jwk", jwk, { name: "ECDSA", namedCurve: "P-256" }, true, ["verify"]);Match the curve to the key.
      How-toBrowser: export SPKIconst spki = await crypto.subtle.exportKey("spki", key);Returns an ArrayBuffer. Wrap its base64 in PEM lines.
      How-toBrowser: export a JWKconst jwk = await crypto.subtle.exportKey("jwk", key);The key must have been imported as extractable.
      How-toBrowser: base64 from an ArrayBufferconst b64 = btoa(String.fromCharCode(...new Uint8Array(spki)));Add -----BEGIN PUBLIC KEY----- lines and a line break every 64 characters.
      How-toPython cryptography: load a PEM public keyfrom cryptography.hazmat.primitives import serialization key = serialization.load_pem_public_key(pem_bytes)Returns a public key object.
      How-toPython jwcrypto: PEM to JWKfrom jwcrypto import jwk key = jwk.JWK.from_pem(pem_bytes) print(key.export_public())Prints the public JWK as JSON.
      How-toPython jwcrypto: JWK to PEMpem = key.export_to_pem()Add private_key=True to export the private key.
      How-toPyJWT: RSA key from a JWKimport json, jwt public_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(jwk))Returns a key you can pass to jwt.decode.
      How-toPyJWT: EC key from a JWKpublic_key = jwt.algorithms.ECAlgorithm.from_jwk(json.dumps(jwk))Use it for ES256, ES384 and ES512 tokens.
      How-toPyJWT: JWKS clientclient = jwt.PyJWKClient("https://auth.example.com/.well-known/jwks.json") signing_key = client.get_signing_key_from_jwt(token)Fetches the JWKS and picks the key by kid.
      How-toJava Nimbus: parse a PEMJWK jwk = JWK.parseFromPEMEncodedObjects(pem);From the Nimbus JOSE + JWT library. Check your version.
      How-toJava Nimbus: load a JWKSJWKSet set = JWKSet.load(new URL(jwksUri));Loads the key set from a URL. Newer versions offer other loaders.
      How-toPHP firebase/php-jwt$keys = JWK::parseKeySet(json_decode($jwksJson, true));Returns keys indexed by kid.
      How-toRuby ruby-jwtpublic_key = JWT::JWK.import(jwk_hash).public_keyImports a JWK hash and returns the OpenSSL key.
      How-to.NET JsonWebKeySetvar jwks = new JsonWebKeySet(json); var key = jwks.Keys.First(k => k.Kid == kid);From Microsoft.IdentityModel.Tokens.
      How-toGo jwx librarygo get github.com/lestrrat-go/jwx/v2/jwkA Go library for JWK handling. Check the docs of your version.
      How-toList the kids with jqcurl -s https://auth.example.com/.well-known/jwks.json | jq -r '.keys[].kid'Prints one kid per line.
      How-toSelect one key by kidjq '.keys[] | select(.kid == "key-1")' jwks.jsonPrints the matching key.
      How-toCount the keysjq '.keys | length' jwks.jsonPrints the number of keys.
      How-toList kid, kty and algjq -r '.keys[] | "\(.kid) \(.kty) \(.alg)"' jwks.jsonA compact overview of all keys.
      SecurityRemove private fields from a JWKjq 'del(.d, .p, .q, .dp, .dq, .qi)' private-jwk.jsonLeaves only the public members.
      How-toFetch a JWKS in JavaScriptconst jwks = await fetch(jwksUri).then((r) => r.json());Works in browsers (with CORS) and in Node.js 18 or later.
      How-toHow often should I refresh a JWKS?Cache-Control: public, max-age=3600Follow the server’s caching headers, and refetch once when you see an unknown kid.
      SecurityRotate signing keys// publish new + old key, sign with the new key, remove the old one after its tokens expireOverlap the keys so tokens signed with the old key stay valid until they expire.
      How-toMatch a token to a keyconst key = jwks.keys.find((k) => k.kid === header.kid);Use the kid from the token header.
      How-toToken header example{ "alg": "RS256", "typ": "JWT", "kid": "key-1" }The kid points to a key in the JWKS.
      ErrorNo matching key for kidconst key = jwks.keys.find((k) => k.kid === header.kid);Refetch the JWKS once, and check that the token comes from the right issuer.
      ErrorPEM routines: no start line-----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----The text is not valid PEM. Check the BEGIN and END lines and the line breaks.
      ErrorPEM with Windows line endingstr -d '\r' < key.pem > key-unix.pemCRLF line endings can break some parsers. This tool accepts both.
      ErrorUnknown key type error"kty": "RSA"Check kty. Only RSA, EC, OKP and oct are defined for JWK.
      ErrorSignature verification failed// check kid, alg, key type and issuerTypical causes: the wrong key, the wrong alg, a key from another tenant, or a changed token.
      ErrorInvalid base64url in a JWK"n": "0vx7ago..." // no "=", "+" or "/"Remove padding, and replace + and / with - and _.
      ErrorEC point is not on the curve// x and y do not satisfy the curve equationThe key is corrupt, or the coordinates are swapped or cut short. The tool checks this.
      ErrorWrong PEM label-----BEGIN RSA PRIVATE KEY----- vs -----BEGIN PRIVATE KEY-----The label tells which DER format is inside. Do not change a label by hand.
      ErrorEncrypted private key-----BEGIN ENCRYPTED PRIVATE KEY-----Decrypt it first with openssl. The tool never asks for a passphrase.
      ErrorJWKS with an empty keys array{ "keys": [] }Verification always fails. Publish at least one key.
      ErrorDuplicate kid values"kid": "key-1" // used twiceA verifier cannot tell which key to use. Give every key a unique kid.
      SecurityPrivate key in a public JWKS"d": "..." // never publishIf you published one, treat the key as compromised and rotate it.
      SecurityPublish only public keysjq 'del(.d, .p, .q, .dp, .dq, .qi)'Strip private members before you publish. Turn on Public keys only in the tool.
      SecurityDo not use a public key as an HMAC secret// accept only the algorithms you expectIn an algorithm confusion attack, a forged HS256 token is verified with the public key. Pin the allowed algorithms.
      SecurityDo not trust jku or x5u headers from tokens// ignore jku and x5u unless you allow-list the URLA token can point to a key set that an attacker controls.
      SecurityFetch a JWKS only from trusted URLsconst JWKS_URI = "https://auth.example.com/.well-known/jwks.json";Take the URL from your configured issuer’s discovery document.
      SecurityStore private keys safely// use a KMS or HSM, not source controlNever commit private keys to a repository.
      SecurityAvoid pasting production private keys anywhere// generate a test key insteadThis tool runs in your browser, but a test key is safer for experiments.

      FAQ

      QuestionAnswer
      What is a JWKS?A JWK Set (JWKS) is a JSON object with a keys array of JSON Web Keys (RFC 7517). Identity providers publish one at their jwks_uri so applications can verify the signatures of tokens.
      How do I convert a JWK to PEM?Paste a JWK or a JWKS into the tool. It converts RSA, EC (P-256, P-384, P-521) and Ed25519 or X25519 keys into PEM. Public keys become PUBLIC KEY blocks (SPKI). If you turn off Public keys only and the input has a private key, you also get a PRIVATE KEY block (PKCS#8).
      How do I convert a PEM key to a JWK?Paste the PEM into the tool. It reads PUBLIC KEY, RSA PUBLIC KEY, PRIVATE KEY, RSA PRIVATE KEY and EC PRIVATE KEY blocks and returns a JWKS. You can add a kid from the key’s RFC 7638 thumbprint, and add use and alg values.
      What is a JWK thumbprint and why use it as a kid?A JWK thumbprint (RFC 7638) is the base64url SHA-256 hash of the key’s required members written as JSON in a fixed order. It always gives the same value for the same key, so it works well as a stable kid.
      Why does the tool report an error for a private key in my JWKS?A public JWKS must never contain private members such as d, p, q, dp, dq, qi or k. If you already published a private key, treat it as compromised and rotate it.
      Is it safe to paste my keys here?The conversion runs entirely in your browser and nothing is uploaded. Still, avoid pasting production private keys into any web page. The Share link button puts your input in the URL, so never share a link that contains a private key.