Search code examples
javasecurityjwtjjwt

how to load Private Key from .key file


I would like to load PrivateKey from a .key file and use it to generate jwt token. I have following method to generate token

    public String gen(String privateFile, String crtFile) {

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        long expMillis = nowMillis + 50000;
        Date exp = new Date(expMillis);

        // load private key
        PrivateKey privKey= loadPrivateKey(privateFile);
        // load public key
        PublicKey pubKey= loadPublicKey(crtFile);

        String jws = Jwts.builder()
                .setSubject(jwtSubject)
                .setAudience(jwtAudience)
                .setExpiration(exp)
                .setIssuedAt(now)
                .setIssuer(jwtIssuer)
                .setNotBefore(now)
                .signWith(privKey, SignatureAlgorithm.RS512)
                .compact();

        return jws;

}

loadPrivateKey method looks as follows:

    public static PrivateKey loadPrivateKey(String filename)
        throws Exception {

    String privateKeyContent = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource(filename).toURI())));
    privateKeyContent = privateKeyContent.replaceAll("\\n", "").replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "");

    KeyFactory kf = KeyFactory.getInstance("RSA");
    PKCS8EncodedKeySpec keySpecPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyContent));

    PrivateKey privKey = kf.generatePrivate(keySpecPKCS8);
    return privKey;

}

On the compilation I get java.io.IOException: Invalid keystore format at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:663) at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56) at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224) at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)

Which I do not understand because I am opening PKCS8 private key. Would someone have an idea how to solve this?


Solution

  • I hope this will help you to generate the token. keep the .key or .der file into classpath src/main/resources.

    public class JWTClientService {
    
        public String generateJWTToken(ProjectConfig jwtConfig) {
            return Jwts.builder()
                    .setSubject(jwtConfig.getSubject())
                    .setIssuer(jwtConfig.getIssuer())
                    .setExpiration(getExpiryDate(jwtConfig.getTokenExpiryUnit(), jwtConfig.getTokenExpiryFrequency()))
                    .setAudience(jwtConfig.getAudience())
                    .claim(jwtConfig.getClaimKey(), Boolean.valueOf(jwtConfig.getClaimValue()))
                    .signWith(SignatureAlgorithm.RS512, privateKey(jwtConfig))
                    .compact();
        }
    
        private Date getExpiryDate(String tokenExp, String tokenExpFreq) {
            Calendar calendar = Calendar.getInstance();
            int expiry = Integer.parseInt(tokenExp);
            switch (tokenExpFreq.toLowerCase()) {
    
                case "second": {
                    calendar.add(Calendar.SECOND, expiry);
                    break;
                }
                case "minute": {
                    calendar.add(Calendar.MINUTE, expiry);
                    break;
                }
                case "hour": {
                    calendar.add(Calendar.HOUR, expiry);
                    break;
                }
                case "day": {
                    calendar.add(Calendar.DATE, expiry);
                    break;
                }
                case "month": {
                    calendar.add(Calendar.MONTH, expiry);
                    break;
                }
                default: {
                    calendar.add(Calendar.HOUR, expiry);
                    break;
                }
            }
            return calendar.getTime();
        }
    
        private PrivateKey privateKey(ProjectConfig jwtConfig) {
            PrivateKey privateKey = null;
            try {
                InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(jwtConfig.getKeyPath());
                ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
                assert inputStream != null;
                IOUtils.copy(inputStream, byteOutputStream);
                byte[] privKeyByteArray = byteOutputStream.toByteArray();
                PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyByteArray);
    
                KeyFactory keyFactory = KeyFactory.getInstance(jwtConfig.getKeyAlgorithm());
    
                privateKey = keyFactory.generatePrivate(keySpec);
            } catch (Exception ex) {
                throw new RuntimeException("Unable to generate private key..." + ex.getMessage());
            }
            return privateKey;
        }
    
    }
    

    Find the Project config class:

     @JsonInclude(JsonInclude.Include.NON_NULL)
        public class ProjectConfig {
            private String clientId;
            private String clientSecret;
            private String jwtTokenUrl;
            private String keyAlgorithm;
            private String keyPath;
            private String subject;
            private String issuer;
            private String audience;
            private String claimKey;
            private String claimValue;
            private String tokenExpiryFrequency;
            private String tokenExpiryUnit;
    
            public String getClientId() {
                return clientId;
            }
    
            public void setClientId(String clientId) {
                this.clientId = clientId;
            }
    
            public String getClientSecret() {
                return clientSecret;
            }
    
            public void setClientSecret(String clientSecret) {
                this.clientSecret = clientSecret;
            }
    
            public String getJwtTokenUrl() {
                return jwtTokenUrl;
            }
    
            public void setJwtTokenUrl(String jwtTokenUrl) {
                this.jwtTokenUrl = jwtTokenUrl;
            }
    
            public String getKeyAlgorithm() {
                return keyAlgorithm;
            }
    
            public void setKeyAlgorithm(String keyAlgorithm) {
                this.keyAlgorithm = keyAlgorithm;
            }
    
            public String getKeyPath() {
                return keyPath;
            }
    
            public void setKeyPath(String keyPath) {
                this.keyPath = keyPath;
            }
    
            public String getSubject() {
                return subject;
            }
    
            public void setSubject(String subject) {
                this.subject = subject;
            }
    
            public String getIssuer() {
                return issuer;
            }
    
            public void setIssuer(String issuer) {
                this.issuer = issuer;
            }
    
            public String getAudience() {
                return audience;
            }
    
            public void setAudience(String audience) {
                this.audience = audience;
            }
    
            public String getClaimKey() {
                return claimKey;
            }
    
            public void setClaimKey(String claimKey) {
                this.claimKey = claimKey;
            }
    
            public String getClaimValue() {
                return claimValue;
            }
    
            public void setClaimValue(String claimValue) {
                this.claimValue = claimValue;
            }
    
            public String getTokenExpiryFrequency() {
                return tokenExpiryFrequency;
            }
    
            public void setTokenExpiryFrequency(String tokenExpiryFrequency) {
                this.tokenExpiryFrequency = tokenExpiryFrequency;
            }
    
            public String getTokenExpiryUnit() {
                return tokenExpiryUnit;
            }
    
            public void setTokenExpiryUnit(String tokenExpiryUnit) {
                this.tokenExpiryUnit = tokenExpiryUnit;
            }
        }
    

    Main Class :

    public class TokenApplication {
        static ObjectMapper objectMapper = new ObjectMapper()
                .configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true);
    
        public static void main(String[] args) {
            ProjectConfig projectConfig = loadConfiguration("application-stg.properties");
    
            if (args.length > 0 && args[0].equals("PROD")) {
                projectConfig = loadConfiguration("application-prod.properties");
            }
            try {
                JWTTokenService jwtTokenService = new JWTTokenService();
                System.out.println(jwtTokenService.getJwtToken(projectConfig).getAccessToken());
                System.exit(JobStatus.SUCCESS.getCode());
            } catch (Exception ex) {
                System.exit(JobStatus.PROCESS_FAILED.getCode());
            }
    
        }
    
    
        private static ProjectConfig loadConfiguration(String filePath) {
            try (InputStream input = TokenApplication.class.getClassLoader().getResourceAsStream(filePath)) {
                Properties props = new Properties();
                props.load(input);
                return objectMapper.convertValue(new HashMap(props), ProjectConfig.class);
            } catch (Exception ex) {
                throw new RuntimeException("Not able to load configuration" + ex.getMessage());
            }
        }
    
    }
    

    application-stg.properties

    keyAlgorithm=RSA
    keyPath=private-stage.der
    subject=
    issuer=
    audience=
    claimKey=
    claimValue=true
    tokenExpiryFrequency=DAY
    tokenExpiryUnit=1
    clientId=
    clientSecret=
    jwtTokenUrl=