{"id":16179196,"url":"https://github.com/jonashackt/spring-boot-rest-clientcertificate","last_synced_at":"2025-10-08T11:41:07.097Z","repository":{"id":39096441,"uuid":"110079416","full_name":"jonashackt/spring-boot-rest-clientcertificate","owner":"jonashackt","description":"Example project showing how to provide a Spring Boot App that serves a secured REST endpoint, that is called with Spring´s RestTemplate configured to use client authentification with a client certificate","archived":false,"fork":false,"pushed_at":"2025-03-21T06:02:41.000Z","size":54,"stargazers_count":94,"open_issues_count":6,"forks_count":60,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T05:09:05.283Z","etag":null,"topics":["client-certificate","crt","java-keystore","jks","key","resttemplate-configuration","spring-boot","spring-resttemplate","truststore"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonashackt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-09T07:00:00.000Z","updated_at":"2025-01-26T11:39:39.000Z","dependencies_parsed_at":"2024-01-19T22:41:25.321Z","dependency_job_id":"bb71c11a-40a2-4543-9aec-f6120c130b69","html_url":"https://github.com/jonashackt/spring-boot-rest-clientcertificate","commit_stats":{"total_commits":54,"total_committers":3,"mean_commits":18.0,"dds":0.537037037037037,"last_synced_commit":"8b3a6c8e1c93a42fb9dc3244b573213208f1e3c8"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonashackt%2Fspring-boot-rest-clientcertificate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonashackt%2Fspring-boot-rest-clientcertificate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonashackt%2Fspring-boot-rest-clientcertificate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonashackt%2Fspring-boot-rest-clientcertificate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonashackt","download_url":"https://codeload.github.com/jonashackt/spring-boot-rest-clientcertificate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247294540,"owners_count":20915340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-certificate","crt","java-keystore","jks","key","resttemplate-configuration","spring-boot","spring-resttemplate","truststore"],"created_at":"2024-10-10T05:25:54.821Z","updated_at":"2025-10-08T11:41:02.064Z","avatar_url":"https://github.com/jonashackt.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"REST Client uses clientcertificate to authenticate to Spring Boot Server\n=============================\n[![Build Status](https://github.com/jonashackt/spring-boot-rest-clientcertificate/workflows/github/badge.svg)](https://github.com/jonashackt/spring-boot-rest-clientcertificate/actions)\n[![renovateenabled](https://img.shields.io/badge/renovate-enabled-yellow)](https://renovatebot.com)\n\nThis project implements a basic example using Spring Boot as the certificate secured server and also as the client calling this server accordingly - everything only has one private key and certificate. If you´re looking for a more advanced example on how a Spring Boot App could call more then one secured server using multiple client certificates, have a look at this project here: [jonashackt/spring-boot-rest-clientcertificates-docker-compose](https://github.com/jonashackt/spring-boot-rest-clientcertificates-docker-compose).\n\nIf you only frequently use some sec-technologies like me, then you maybe need a refresher to what was what in this world :) For all the file formats like .crt, .cert, .pem, .key, .pkcs12/.pfx/.p12 read this post: https://serverfault.com/a/9717\n\nAnd here´s an explanation of the difference between the 2 Java Keystore-Options (Keystore.jks and Truststore.jks): https://stackoverflow.com/a/6341566/4964553\n\n\n# Generate the usual .key and .crt - and import them into needed Keystore .jks files\n\nFor the app here, you need the following files, if you want to fully want to go through all the steps (you need `openssl`and a `jdk` installed):\n\n\u003e Please make sure to always use the same password for all artifacts! This is needed later, because Tomcat needs the same password for the key and the keystores (see https://stackoverflow.com/a/23979014/4964553).\n\n\n#### 1. generate Private Key: exampleprivate.key\n\n```\nopenssl genrsa -des3 -out exampleprivate.key 1024\n```\n\n- enter a passphrase for the key, in this example I used `allpassword`\n\n\n#### 2. generate Certificate Signing Request (CSR): example.csr\n\n```\nopenssl req -new -key exampleprivate.key -out example.csr\n```\n\nThis will bring up some questions you should answer according to the X.509 standard. You can nearly answer anything as you want to, but be sure to mind the `Common Name`. Because a certificate is always issued for a certain domain and in this example our Spring Boot server uses `localhost` here, we have to issue this accordingly. Otherwise you´ll get the following exception (see https://stackoverflow.com/questions/8839541/hostname-in-certificate-didnt-match also):\n\n```\nCaused by: javax.net.ssl.SSLPeerUnverifiedException: Certificate for \u003clocalhost\u003e doesn't match any of the subject alternative names: []\n\tat org.apache.http.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:467)\n\tat org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:397)\n\tat org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)\n\tat org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)\n\tat org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:359)\n\tat org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)\n\tat org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)\n\tat org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)\n\tat org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)\n\tat org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)\n\tat org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)\n\tat org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)\n\tat org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)\n\tat org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:89)\n\tat org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)\n\tat org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)\n\tat org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652)\n```\n\nThere´s also a X.509 extension that allows to configure a certificate to support multiple domains (with the Subject Alternative Names (SAN) parameter) - but we won´t use this here. See https://www.digicert.com/subject-alternative-name.htm for more information.\n\n```\nEnter pass phrase for exampleprivate.key:\nYou are about to be asked to enter information that will be incorporated\ninto your certificate request.\nWhat you are about to enter is what is called a Distinguished Name or a DN.\nThere are quite a few fields but you can leave some blank\nFor some fields there will be a default value,\nIf you enter '.', the field will be left blank.\n-----\nCountry Name (2 letter code) [AU]:US\nState or Province Name (full name) [Some-State]:Bayern\nLocality Name (eg, city) []:Munich\nOrganization Name (eg, company) [Internet Widgits Pty Ltd]:TheExampleInc\nOrganizational Unit Name (eg, section) []:SectionX\nCommon Name (e.g. server FQDN or YOUR name) []:localhost\nEmail Address []:max.muller@example.com\n\nPlease enter the following 'extra' attributes\nto be sent with your certificate request\nA challenge password []:\nAn optional company name []:\n```\n\n\n#### 3. generate self-signed Certificate: example.crt\n\n```\nopenssl x509 -req -days 3650 -in example.csr -signkey exampleprivate.key -out example.crt\n```\n\n\n#### 4. create a Java Truststore Keystore, that inherits the generated self-signed Certificate: truststore.jks\n\n```\nkeytool -import -file example.crt -alias exampleCA -keystore truststore.jks\n```\n\nYou´re promted for a password again - be sure to use __the same password__ like the key´s one (I used `allpassword` here).\n\n\n#### 5. create a Java Keystore, that inherits Public and Private Keys (keypair): keystore.jks\n\nSince the [JDK´s keytool can´t import a Private Key directly](https://www.softteco.com/blog/create-java-keystore-file-from-existing-private-key-and-certificate/), we need to create a importable container format first - the `keystore.p12`: \n\n```\nopenssl pkcs12 -export -in example.crt -inkey exampleprivate.key -certfile example.crt -name \"examplecert\" -out keystore.p12\n```\n\nYou´re promted for a password again - be sure to use __the same password__ like the key´s one (I used `allpassword` here).\n\nYou could stop here and just use the `keystore.p12` instead of the `keystore.jks` variant generated in the next step. It´ up to you, the implementation also supports `.loadKeyMaterial(ResourceUtils.getFile(\"classpath:keystore.p12\"), allPassword, allPassword)`\n\n\n```\nkeytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype JKS\n```\n\nYou´re promted for a password again - be sure to use __the same password__ like the key´s one (I used `allpassword` here). You´re also prompted for the exportpassword, which is `allpassword` again. Then finally, we have all files ready to implement our server.\n\n\n# Configure the example Server\n\nCopy the generated `keystore.jks` and `truststore.jks` into `src/main/resources` and - for showing a complete Testexample - also into `src/test/resources`\n\nAlso we need to configure the Server to provide the needed secured REST endpoint. There are some steps we need to take here:\n\n#### 1. Import spring-boot-starter-security\n\nAdd the following to the pom.xml:\n\n```\n   \u003c!-- we need this here for server certificate handling --\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.springframework.boot\u003c/groupId\u003e\n        \u003cartifactId\u003espring-boot-starter-security\u003c/artifactId\u003e\n    \u003c/dependency\u003e\n```\n\n#### 2. Configure the application.yml\n\n```\nserver:\n  port: 8443\n  ssl:\n    key-store: classpath:keystore.jks\n    key-store-password: allpassword\n    trust-store: classpath:truststore.jks\n    trust-store-password: allpassword\n    client-auth: need\nsecurity:\n  headers:\n    hsts: NONE\n```\n\n#### 3. Create @Configuration annotated WebSecurityConfig\n\nSee [WebSecurityConfig.java](src/main/java/de/jonashackt/configuration/WebSecurityConfig.java)\n\n#### 4. Create a normal Spring MVC REST endpoint\n\nSee [ServerController.java](src/main/java/de/jonashackt/controller/ServerController.java)\n\n\nYour Server should now be ready to serve a Client certificate secured REST endpoint.\n\n\n# Run the example Server and access it with the Spring RestTemplate\n\nTo access a client certificate secured REST endpoint with the Spring RestTemplate, you also have to do a few more steps than usual:\n\n#### 1. import org.apache.httpcomponents.httpclient into the pom.xml\n\n```\n\t\u003c!-- we need httpclient here for client certificate handling --\u003e\n\t\u003cdependency\u003e\n\t\t\u003cgroupId\u003eorg.apache.httpcomponents\u003c/groupId\u003e\n\t\t\u003cartifactId\u003ehttpclient\u003c/artifactId\u003e\n\t\u003c/dependency\u003e\n```\n\n#### 2. Create a @Configuration annotated class for the RestTemplate configuration:\n\nSee [RestClientCertTestConfiguration.java](src/test/java/de/jonashackt/RestClientCertTestConfiguration.java) or directly:\n\n```\npackage de.jonashackt.restexamples;\n\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.conn.ssl.NoopHostnameVerifier;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.ssl.SSLContextBuilder;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.web.client.RestTemplateBuilder;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.Resource;\nimport org.springframework.http.client.HttpComponentsClientHttpRequestFactory;\nimport org.springframework.util.ResourceUtils;\nimport org.springframework.web.client.RestTemplate;\n\nimport javax.net.ssl.SSLContext;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.InputStream;\nimport java.security.KeyStore;\n\n@Configuration\npublic class RestClientCertTestConfiguration {\n\n    private String allPassword = \"allpassword\";\n\n    @Bean\n    public RestTemplate restTemplate(RestTemplateBuilder builder) throws Exception {\n\n        SSLContext sslContext = SSLContextBuilder\n                .create()\n                .loadKeyMaterial(ResourceUtils.getFile(\"classpath:keystore.jks\"), allPassword.toCharArray(), allPassword.toCharArray())\n                .loadTrustMaterial(ResourceUtils.getFile(\"classpath:truststore.jks\"), allPassword.toCharArray())\n                .build();\n\n        HttpClient client = HttpClients.custom()\n                .setSSLContext(sslContext)\n                .build();\n\n        return builder\n                .requestFactory(new HttpComponentsClientHttpRequestFactory(client))\n                .build();\n    }\n}\n```\n\n#### 3. Create a common Test.class using the RestTemplate with @Autowired\n\nSee [RestClientCertTest.java](src/test/java/de/jonashackt/RestClientCertTest.java) or directly:\n\n```\npackage de.jonashackt.restexamples;\n\nimport ServerController;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.context.embedded.LocalServerPort;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.web.client.RestTemplate;\n\nimport static org.junit.Assert.assertEquals;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(\n\t\tclasses = ServerApplication.class,\n\t\twebEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT\n)\npublic class RestClientCertTest {\n\n\t@LocalServerPort\n\tprivate int port;\n\n\t@Autowired\n    private RestTemplate restTemplate;\n\n\t@Test\n\tpublic void is_hello_resource_callable_with_client_cert() {\n\t\tString response = restTemplate.getForObject(\"https://localhost:\" + port + \"/restexamples/hello\", String.class);\n\t    \n\t    assertEquals(ServerController.RESPONSE, response);\n\t}\n}\n\n```\n\nThat´s all! Now you can access a client certificate secured REST endpoint with the Spring RestTemplate!\n\n\n## Links\n\nEvery file extension explained: https://stackoverflow.com/a/6341566/4964553\n\nReally good graphical tool for handling all the different files: http://keystore-explorer.org/\n\nCreate .key, .csr \u0026 .crt with openssl: https://www.akadia.com/services/ssh_test_certificate.html","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonashackt%2Fspring-boot-rest-clientcertificate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonashackt%2Fspring-boot-rest-clientcertificate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonashackt%2Fspring-boot-rest-clientcertificate/lists"}