String generateJwtAssertion() {
        final long utcPlusWindow = Clock.systemUTC().millis() / 1000 + JWT_CLAIM_WINDOW;
        final String audience = config.getJwtAudience() != null ? config.getJwtAudience() : config.getLoginUrl();

        final StringBuilder claim = new StringBuilder().append("{\"iss\":\"").append(config.getClientId())
                .append("\",\"sub\":\"").append(config.getUserName())
                .append("\",\"aud\":\"").append(audience).append("\",\"exp\":\"").append(utcPlusWindow)
                .append("\"}");

        final StringBuilder token = new StringBuilder(JWT_HEADER).append('.')
                .append(Base64.getUrlEncoder().encodeToString(claim.toString().getBytes(StandardCharsets.UTF_8)));

        final KeyStoreParameters keyStoreParameters = config.getKeystore();
        keyStoreParameters.setCamelContext(camelContext);

        try {
            final KeyStore keystore = keyStoreParameters.createKeyStore();

            final Enumeration<String> aliases = keystore.aliases();
            String alias = null;
            while (aliases.hasMoreElements()) {
                String tmp = aliases.nextElement();
                if (keystore.isKeyEntry(tmp)) {
                    if (alias == null) {
                        alias = tmp;
                    } else {
                        throw new IllegalArgumentException(
                                "The given keystore `" + keyStoreParameters.getResource()
                                                           + "` contains more than one key entry, expecting only one");
                    }
                }
            }

            PrivateKey key = (PrivateKey) keystore.getKey(alias, keyStoreParameters.getPassword().toCharArray());

            Signature signature = Signature.getInstance(JWT_SIGNATURE_ALGORITHM);
            signature.initSign(key);
            signature.update(token.toString().getBytes(StandardCharsets.UTF_8));
            byte[] signed = signature.sign();

            token.append('.').append(Base64.getUrlEncoder().encodeToString(signed));

            // Clean the private key from memory
            try {
                key.destroy();
            } catch (javax.security.auth.DestroyFailedException ex) {
                LOG.debug("Error destroying private key: {}", ex.getMessage());
            }
        } catch (IOException | GeneralSecurityException e) {
            throw new IllegalStateException(e);
        }

        return token.toString();
    }
@Test
    public void shouldGenerateJwtTokens() {
        final SalesforceLoginConfig config
                = new SalesforceLoginConfig("https://login.salesforce.com", "ABCD", "username", parameters, true);

        final SalesforceSession session
                = new SalesforceSession(new DefaultCamelContext(), mock(SalesforceHttpClient.class), TIMEOUT, config);

        final String jwtAssertion = session.generateJwtAssertion();

        assertNotNull(jwtAssertion);
    }