# 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 Secret | Private Key JWT | | --- | --- | --- | | Transmission | Sent every request | Never sent | | Server breach | Secret exposed | Your key safe | | Rotation | Coordinated update | Update 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: ```json { "alg": "PS256", "typ": "JWT" } ``` Payload: ```json { "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 ```http 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 ```bash # 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 ```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 - [RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523) - JWT client authentication - [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication) - private_key_jwt method - [OAuth 2.0 Security BCP](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics) - recommends asymmetric auth