java-jwt with public/private keys
Asked Answered
H

5

21

Auth0 provides two JWT libraries, one for Node: node-jsonwebtoken, and one for Java: java-jwt.

I created the private/public key pair, and used it successfully in Node with node-jsonwebtoken:

var key = fs.readFileSync('private.key');
var pem = fs.readFileSync('public.pem');

var header = {...};
var payload = {...};

header.algorithm = "RS256";
var message = jsonwebtoken.sign(payload, key, header);
var decoded = jsonwebtoken.verify(message, pem, {algorithm: "RS256"});

But I found no way of doing the same in Java with java-jwt.

Anyone has a working example of how to use private/public keys for JWT in Java?

Hagiocracy answered 9/6, 2016 at 9:33 Comment(1)
Hi Predrag, I have the same requirement where I have to create a signed token with private key using java and verify the token with public key in node JS .. I am struck with how to load the privatekey (private key.pem) file and create the signed token with RS256 algorithm.. it would be great if you share any samples.Deina
C
2

That particular library doesn't support it. But you can check others for Java that do. See here: https://jwt.io/

Caesalpiniaceous answered 9/6, 2016 at 15:33 Comment(0)
H
35

I used the following code for JWT in Java. Try it.

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

public class JWTJavaWithPublicPrivateKey {

    public static void main(String[] args) {

        System.out.println("generating keys");
        Map<String, Object> rsaKeys = null;

        try {
            rsaKeys = getRSAKeys();
        } catch (Exception e) {

            e.printStackTrace();
        }
        PublicKey publicKey = (PublicKey) rsaKeys.get("public");
        PrivateKey privateKey = (PrivateKey) rsaKeys.get("private");

        System.out.println("generated keys");

        String token = generateToken(privateKey);
        System.out.println("Generated Token:\n" + token);

        verifyToken(token, publicKey);

    }

    public static String generateToken(PrivateKey privateKey) {
        String token = null;
        try {
            Map<String, Object> claims = new HashMap<String, Object>();

            // put your information into claim
            claims.put("id", "xxx");
            claims.put("role", "user");
            claims.put("created", new Date());

            token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.RS512, privateKey).compact();


        } catch (Exception e) {
            e.printStackTrace();
        }
        return token;
    }

    // verify and get claims using public key

    private static Claims verifyToken(String token, PublicKey publicKey) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();

            System.out.println(claims.get("id"));
            System.out.println(claims.get("role"));

        } catch (Exception e) {

            claims = null;
        }
        return claims;
    }

    // Get RSA keys. Uses key size of 2048.
    private static Map<String, Object> getRSAKeys() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        Map<String, Object> keys = new HashMap<String, Object>();
        keys.put("private", privateKey);
        keys.put("public", publicKey);
        return keys;
    }
}
Maven Dependency

<dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.6.0</version>
</dependency>
Hind answered 22/2, 2018 at 10:7 Comment(4)
how can we use existing key, (already generated keys, stored in files)?Sazerac
byte[] b1 = Base64.getDecoder().decode(privateKeyString); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(b1); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey privateKey = kf.generatePrivate(spec);Extempore
This helped me a lot while trying to get the private key read from the external file such as application.yml in my case. Thanks @ExtemporeBreather
Use an existing key. read it from a file and then process validation.Braddock
P
15

Recent versions (since 3.0.0) of the auth0 java-jwt library supports RSA and ECDSA for signing JWT tokens using a public/private key pair.

Example of signing a JWT using java-jwt (based on the documentation).

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;

class JwtPKSigningExample {
    public static void main(String[] args) throws Exception {
        Map<String, Object> keys = generateRSAKeys();

        String token = null;
        try {
            RSAPrivateKey privateKey = (RSAPrivateKey) keys.get("private");
            Algorithm algorithm = Algorithm.RSA256(null, privateKey);
            token = JWT.create()
                    .withIssuer("pk-signing-example")
                    .sign(algorithm);
        } catch (JWTCreationException x) {
            throw x;
        }

        try {
            RSAPublicKey publicKey = (RSAPublicKey) keys.get("public");
            Algorithm algorithm = Algorithm.RSA256(publicKey, null);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer("pk-signing-example")
                    .build();
            DecodedJWT jwt = verifier.verify(token);

            System.out.println(jwt.getToken());
        } catch (JWTVerificationException x) {
            throw x;
        }
    }

    private static Map<String, Object> generateRSAKeys() throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        return Map.of("private", keyPair.getPrivate(), "public", keyPair.getPublic());
    }
}
Paramaribo answered 30/5, 2019 at 21:48 Comment(0)
C
2

That particular library doesn't support it. But you can check others for Java that do. See here: https://jwt.io/

Caesalpiniaceous answered 9/6, 2016 at 15:33 Comment(0)
B
1
    package com.java;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Enumeration;

import org.jose4j.json.internal.json_simple.parser.ParseException;
import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.MalformedClaimException;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.keys.resolvers.JwksVerificationKeyResolver;
import org.jose4j.keys.resolvers.VerificationKeyResolver;
import org.jose4j.lang.JoseException;

public class JWTSigningAndVerification {

    public static void main(String args[]) throws Exception {

        String jwt = generateJWT();
        validateJWTwithJWKS(jwt);
    }

    private static String generateJWT() throws FileNotFoundException, KeyStoreException, IOException,
            NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, JoseException {

        JwtClaims jwt_claims = new JwtClaims();

        jwt_claims.setSubject("sub");
        jwt_claims.setIssuer("https://domain");
        jwt_claims.setIssuedAtToNow();
        jwt_claims.setExpirationTimeMinutesInTheFuture(1000000);
        jwt_claims.setGeneratedJwtId();
        jwt_claims.setClaim("sid", "sessionid");
        jwt_claims.setClaim("email", "[email protected]");
        jwt_claims.setClaim("given_name", "first");
        jwt_claims.setClaim("family_name", "last");

        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload(jwt_claims.toJson());
        String KeyPassword = "p12-key-password";
        File file = new File("path-to-key.p12");
        InputStream stream = new FileInputStream(file);
        KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
        store.load(stream, KeyPassword.toCharArray());
        Enumeration e = store.aliases();
        String alias = (String) e.nextElement();
        PrivateKey key = (PrivateKey) store.getKey(alias, KeyPassword.toCharArray());
        jws.setKey(key);
        jws.setKeyIdHeaderValue("1");
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_PSS_USING_SHA512);
        jws.setHeader("typ", "JWT");

        String jwt = jws.getCompactSerialization();
        System.out.println(jwt);

        return jwt;
    }

    private static void validateJWTwithJWKS(String jwt) throws JoseException, FileNotFoundException, IOException,
            ParseException, InvalidJwtException, MalformedClaimException {

        JsonWebKeySet jsonWebKeySet = new JsonWebKeySet("json-jwks-escaped");
        VerificationKeyResolver verificationKeyResolver = new JwksVerificationKeyResolver(jsonWebKeySet.getJsonWebKeys());

        JwtConsumer jwtConsumer = new JwtConsumerBuilder().setVerificationKeyResolver(verificationKeyResolver).build();

        JwtClaims claims = jwtConsumer.processToClaims(jwt);
        System.out.println("sub:- " + claims.getSubject());
    }

}
Blazer answered 5/10, 2020 at 10:16 Comment(1)
This code block can be used to sign a JWT and verify it using JWKS using jose4j library, let me know if you face any issues using it.Blazer
I
0

If you have public key and private key pem files.

openssl genrsa -aes128 -passout pass:REPLACE_THIS -out privkey.pem 4096
openssl rsa -in privkey.pem -passin pass:REPLACE_THIS -pubout -out public_key.pem

In Java code, include below depedency in pom.xml:

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk18on</artifactId>
        <version>1.78</version>
    </dependency>

Credit to answer at link Github Gist

Create this class:

package com.zzz.xxx.util;

import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class PublicPrivateKey {
    // using bouncycastle to generate public key
    public static PublicKey getPublicKey() throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
        KeyFactory factory = KeyFactory.getInstance("RSA");
        File file = new File("E:\\PATH\\public_key.pem");
        try (FileReader keyReader = new FileReader(file); PemReader pemReader = new PemReader(keyReader)) {
            PemObject pemObject = pemReader.readPemObject();
            byte[] content = pemObject.getContent();
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
            PublicKey publicKey = factory.generatePublic(pubKeySpec);
            return publicKey;
        }
    }

    public static PrivateKey getPrivateKey() throws InvalidKeySpecException, NoSuchAlgorithmException, IOException {
        KeyFactory factory = KeyFactory.getInstance("RSA");
        File file = new File("E:\\PATH\\private_key.pem");
        try (FileReader keyReader = new FileReader(file); PemReader pemReader = new PemReader(keyReader)) {
            PemObject pemObject = pemReader.readPemObject();
            byte[] content = pemObject.getContent();
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(content);
            PrivateKey privateKey = factory.generatePrivate(privateKeySpec);
            return privateKey;
        }
    }
}

And then use it where needed (example below):

return Jwts.builder()
        .setSubject(subject)
        .setIssuedAt(new Date())
        .setExpiration(expiryDate)
        //.signWith(SignatureAlgorithm.HS512, appProperties.getAuth().getTokenSecret())
        .signWith(privateKey, SignatureAlgorithm.RS512)
        .compact();
Ifill answered 12/4 at 19:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.