What does the PEM to JWK & JWKS Key Converter do?
The PEM to JWK & JWKS Key Converter transforms standard X.509 SPKI and PKCS#8 PEM public or private keys (-----BEGIN PUBLIC KEY-----, -----BEGIN PRIVATE KEY-----) into RFC 7517 JSON Web Key (JWK) and multi-key JWKS JSON formats. It allows developers building OAuth 2.0 authorization servers, OpenID Connect (OIDC) identity providers, and API gateways to publish their public keys at /.well-known/jwks.json directly from existing OpenSSL certificates.
Core Concepts
Understanding PEM to JWK parameter serialization:
- Modulus (
n) & Exponent (e) Extraction: Decodes ASN.1 DER structures from RSA public keys and converts big-endian integer bytes into Base64URL-encoded strings. - Elliptic Curve Parameterization: Maps ECDSA keys (curves
P-256,P-384,P-521) toxandycoordinate strings and setscrv. - JWKS Packaging: Wraps single or multiple cryptographic keys into standard
{"keys": [...]}JSON sets for compatibility with JWT client libraries.
How to use the tool?
- Paste PEM Certificate: Paste your public key starting with
-----BEGIN PUBLIC KEY-----into the editor or click Load Sample RSA. - Configure Metadata: Enter an optional Key ID (
kid), signing algorithm (RS256,ES256, etc.), key usage (sig), and output format (Single JWK or JWKS). - Convert & Export: Click Convert to JWK JSON to copy the formatted JSON or download
jwks.json.
Related Developer Utilities
If you work with JSON Web Tokens, OAuth 2.0, and cryptographic certificates, explore these complementary tools:
- JWK & JWKS to PEM Public Key Converter: Convert JSON Web Keys back to PEM certificates.
- JWT Expiry & TTL Checker: Inspect JWT timestamps, clock skew, and calculate remaining time-to-live.
- Base64 to Base64URL Converter: Convert standard Base64 strings to URL-safe format without padding.
- SSH Public Key Format Converter: Convert OpenSSH keys to RFC 4716 and PEM formats.
REST API Integration
Blueutils provides a free REST API endpoint (POST https://blueutils.com/api/jwt/pem-to-jwk) to programmatically convert PEM keys into JWK and JWKS JSON formats.
API Request Parameters
| Name | Type | Description | Example |
|---|---|---|---|
rawText |
String | PEM key string (-----BEGIN PUBLIC KEY-----...). |
"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkq..." |
options.kid |
String | Optional Key ID to assign. | "auth-key-2026" |
options.alg |
String | Optional algorithm indicator (RS256, ES256). |
"RS256" |
options.use |
String | Intended key usage (sig or enc). Default: sig. |
"sig" |
API Request Payload Examples
cURL
curl -X POST https://blueutils.com/api/jwt/pem-to-jwk \
-H "Content-Type: application/json" \
-d '{
"rawText": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyN6w9N4I9K2P4V4x_g_xP9Q_mR9w-4wQu1W1to1bXx7_TupaoAYEDBuW3HBAfCEddFsJq6BxbHK0nU7d357M6xWUKKA054ndMQgEKqVCKzZXbq2UdVgTk7EI8t1xEE9zaQ_Z9yY-y0L0VpU4-x0k8R4N7I3l32P4V4x_g_xP9Q_mR9w-4wIDAQAB\n-----END PUBLIC KEY-----",
"options": {
"kid": "rsa-key-1",
"alg": "RS256"
}
}'Python
import requests
url = "https://blueutils.com/api/jwt/pem-to-jwk"
payload = {
"rawText": "-----BEGIN PUBLIC KEY-----\n...",
"options": {
"kid": "rsa-key-1",
"alg": "RS256"
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Main {
public static void main(String[] args) throws Exception {
String jsonPayload = """
{
"rawText": "-----BEGIN PUBLIC KEY-----\\n...",
"options": { "kid": "rsa-key-1" }
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://blueutils.com/api/jwt/pem-to-jwk"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}API Response Parameters
| Name | Type | Description | Example |
|---|---|---|---|
isValid |
Boolean | Indicates whether conversion succeeded. | true |
kty |
String | Cryptographic key type (e.g. RSA, EC). | "RSA" |
jwk |
Object | Full JWK representation object. | { "kty": "RSA", "n": "...", "e": "AQAB" } |
jwks |
Object | Complete JWKS wrapper object ({"keys": [...]}). |
{ "keys": [...] } |
jwkJson |
String | Pretty-printed single JWK JSON string. | "{\n \"kty\": \"RSA\"...}" |
jwksJson |
String | Pretty-printed JWKS set JSON string. | "{\n \"keys\": [...]}" |
API Response Payload Examples
Success Response (HTTP 200 OK)
{
"isValid": true,
"kty": "RSA",
"kid": "rsa-key-1",
"alg": "RS256",
"use": "sig",
"jwk": {
"kty": "RSA",
"n": "yN6w9N4I9K2P4V4x_g_xP9Q_mR9w-4wQu1W1to1b...",
"e": "AQAB",
"kid": "rsa-key-1",
"alg": "RS256",
"use": "sig"
},
"jwks": {
"keys": [
{
"kty": "RSA",
"n": "yN6w9N4I9K2P4V4x_g_xP9Q_mR9w-4wQu1W1to1b...",
"e": "AQAB",
"kid": "rsa-key-1",
"alg": "RS256",
"use": "sig"
}
]
}
}Validation Failure Response (HTTP 400 Bad Request)
{
"isValid": false,
"error": "Invalid PEM format. Expected -----BEGIN PUBLIC KEY----- certificate markers."
}Rate Limit Exceeded Response (HTTP 429 Too Many Requests)
{
"error": "API rate limit exceeded. Please wait or contact support@blueutils.com."
}Why use an API to convert PEM to JWK?
Integrating the PEM to JWK Converter API into key rotation workflows, OAuth provisioning scripts, or AI agent tool calling provides key benefits:
- Automated JWKS Publication: Dynamically converts rotated OpenSSL public keys into RFC 7517 JWKS sets deployed directly to CDN endpoints.
- Optimized Token Efficiency for AI Agents: LLMs struggle with converting binary ASN.1 structures into Base64URL BigIntegers. Calling the API ensures 100% syntactically valid JWK objects deterministically.
- Seamless IdP Integration: Provides standard JSON Web Keys for frameworks like Node.js
oidc-provider, Pythonauthlib, and Java Spring Security.
Native Usage
How to convert PEM to JWK natively:
Linux / Unix (Node.js)
# Convert PEM to JWK via native Node.js crypto
node -e '
const fs = require("fs");
const crypto = require("crypto");
const pem = fs.readFileSync("public_key.pem", "utf8");
const jwk = crypto.createPublicKey(pem).export({ format: "jwk" });
console.log(JSON.stringify({ keys: [jwk] }, null, 2));
' > jwks.jsonWindows (PowerShell)
# Convert PEM to JWK in PowerShell using Node.js
node -e "const fs = require('fs'); const crypto = require('crypto'); const pem = fs.readFileSync('public_key.pem', 'utf8'); console.log(JSON.stringify({ keys: [crypto.createPublicKey(pem).export({ format: 'jwk' })] }, null, 2))" | Out-File -Encoding utf8 jwks.jsonWindows (Command Prompt)
:: Generate JWKS file from PEM using Node.js
node -e "const fs = require('fs'); const crypto = require('crypto'); console.log(JSON.stringify(crypto.createPublicKey(fs.readFileSync('public_key.pem', 'utf8')).export({ format: 'jwk' }), null, 2))" > jwk.jsonPython
Using cryptography:
import base64
import json
from cryptography.hazmat.primitives import serialization
def pem_to_jwk(pem_str, kid="key-1"):
pubkey = serialization.load_pem_public_key(pem_str.encode())
public_numbers = pubkey.public_numbers()
n_b64 = base64.urlsafe_b64encode(public_numbers.n.to_bytes((public_numbers.n.bit_length() + 7) // 8, 'big')).decode().rstrip('=')
e_b64 = base64.urlsafe_b64encode(public_numbers.e.to_bytes((public_numbers.e.bit_length() + 7) // 8, 'big')).decode().rstrip('=')
return {
"kty": "RSA",
"n": n_b64,
"e": e_b64,
"kid": kid,
"use": "sig"
}Java
Using Java RSAPublicKey:
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
public class PemToJwkExample {
public static String encodeParam(byte[] bytes) {
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}
}