Skip to content

Private Key JWT

Private Key JWT lets you authenticate using asymmetric cryptography instead of a shared secret.


Why Private Key JWT?

Traditional OAuth uses a client_secret - a password shared between you and the auth server. Problems with this:

  • Secrets leak through logs, config files, git history
  • If the server is breached, your secret is exposed
  • Rotating a compromised secret requires coordination
  • The secret gets sent over the network on every request

With Private Key JWT, you keep a private key and share only the public key with Jiko. To authenticate, you sign a JWT with your private key. Jiko verifies it with your public key.

The private key never leaves your infrastructure.

Client SecretPrivate Key JWT
TransmissionSent every requestNever sent
Server breachSecret exposedYour key safe
RotationCoordinated updateUpdate independently

How It Works

  1. Sign a JWT with your private key
  2. Send it as client_assertion in token requests
  3. Jiko verifies the signature with your public key

JWT Structure

Header:

{
  "alg": "PS256",
  "typ": "JWT"
}

Payload:

{
  "iss": "your-client-id",
  "sub": "your-client-id",
  "aud": "https://auth.jiko.io/api/oauth2/token",
  "iat": 1711910400,
  "exp": 1711910700,
  "jti": "unique-token-id"
}
  • iss / sub - your client ID
  • aud - the token endpoint
  • iat / exp - issued/expiry time (keep it under 5 minutes)
  • jti - unique ID to prevent replay

Token Request

POST /api/oauth2/token HTTP/1.1
Host: auth.jiko.io
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=authorization-code&
client_id=your-client-id&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9...

Generating Keys

OpenSSL

# Generate private key
openssl genrsa -out private_key.pem 2048

# Extract public key
openssl rsa -in private_key.pem -pubout -out public_key.pem

Python

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)

# Save private key
with open("private_key.pem", "wb") as f:
    f.write(private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption()
    ))

# Save public key
with open("public_key.pem", "wb") as f:
    f.write(private_key.public_key().public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo
    ))

Registering Your Key

Add your public key in the Settings page of the Jiko authentication portal. You'll need:

  1. Your public key (PEM format)
  2. Signing algorithm (PS256 or EdDSA recommended)

Keep your private key secure. Don't commit it to git.


Tips

  • Use a secrets manager or HSM in production
  • Keep JWTs short-lived (under 5 minutes)
  • Use unique jti values
  • Rotate keys periodically - register the new one before removing the old

References