How to Securing REST APIs With Client Certificates

How to Securing REST APIs With Client Certificates

This post is about an example of securing a REST API with a client certificate (a.k.a. X.509 certificate authentication). In other words, a client verifies a server according to its certificate and the server identifies that client according to a client certificate

This post is about an example of securing a REST API with a client certificate (a.k.a. X.509 certificate authentication).

In other words, a client verifies a server according to its certificate and the server identifies that client according to a client certificate (so-called mutual authentication).

In connection with Spring Security, we will be able to perform some additional authentication and authorization.

Technologies used:

  1. Spring Boot 2.0.5.RELEASE
  2. Spring Web + Security 5.0.8.RELEASE
  3. Embedded Tomcat 8.5.34

Quick post overview:

  • Create a simple REST API service (without any security)
  • Create certificates for server and client
  • Configure the server to serve HTTPS content
  • Configure the server to require a client certificate
  • Spring Security for further client authentication and authorization
  • Test our secured REST API

Final Project Structure

Creating a New Base Spring Boot Project

We will start with a new project generated by Spring Initializr. We just need two Spring dependencies, i.e. Spring Web + Spring Security.

All required dependencies are shown here:


Create a Simple REST API Service

Let's create a simple REST controller serving a detail about a customer using an HTTP GET method:

public class CustomerController {
    public Customer GetCustomer(@PathVariable Long id) {
        return new Customer(id, "Customer" + id);

Displaying URL http://localhost:8080/customer/1 returns this JSON object:


Create Certificates for Server and Client

I want to stay focused on securing REST APIs so I will show you how to generate all required files in a very concise way. For more details about commands, visit my other blog post about creating a PKCS #12 key store.

#Create folders to generate all files (separated for client and server)
mkdir ssl && cd ssl && mkdir client && mkdir server
## Server
# Generate server private key and self-signed certificate in one step
openssl req -x509 -newkey rsa:4096 -keyout server/serverPrivateKey.pem -out server/server.crt -days 3650 -nodes
# Create PKCS12 keystore containing private key and related self-sign certificate
openssl pkcs12 -export -out server/keyStore.p12 -inkey server/serverPrivateKey.pem -in server/server.crt
# Generate server trust store from server certificate 
keytool -import -trustcacerts -alias root -file server/server.crt -keystore server/trustStore.jks
## Client
# Generate client's private key and a certificate signing request (CSR)
openssl req -new -newkey rsa:4096 -out client/request.csr -keyout client/myPrivateKey.pem -nodes
## Server
# Sign client's CSR with server private key and a related certificate
openssl x509 -req -days 360 -in request.csr -CA server/server.crt -CAkey server/serverPrivateKey.pem -CAcreateserial -out client/pavel.crt -sha256
## Client
# Verify client's certificate
openssl x509 -text -noout -in client/pavel.crt
# Create PKCS12 keystore containing client's private key and related self-sign certificate 
openssl pkcs12 -export -out client/client_pavel.p12 -inkey client/myPrivateKey.pem -in client/pavel.crt -certfile server/myCertificate.crt

We will use files in the server folder to configure our server.

The final client's file client/client_pavel.p12 can be either imported into your browser or used in another client application.

On Windows, just open this file and import it into your system to test the REST API with any browser.

Configure the Server to Serve HTTPS Content

Basically, there are two options.

You can use any standalone server (e.g. Tomcat, WildFly, etc.) so the configuration would be specific to your choice. I prefer this choice for production environments.

Instead of configuring an application server, I will show you the second, simpler way of using an embedded Tomcat server inside Spring Boot.

The configuration is quite easy, we will change the port to 8443 and configure the server key store generated in the previous steps:

# Define a custom port (instead of the default 8080)
# The format used for the keystore
# The path to the keystore containing the certificate
# The password used to generate the certificate

Configure the Server to Require a Client Certificate

The configuration of any server to require a client certificate (i.e. the mutual authentication) is very similar to the server side configuration except using words like a trust store instead of a key store.

So the embedded Tomcat configuration seems like:

# Trust store that holds SSL certificates.
# Password used to access the trust store.
# Type of the trust store.
# Whether client authentication is wanted ("want") or needed ("need").

The embedded server now ensures (without any other configuration) that the clients with a valid certificate only are able to call our REST API.

Other clients will be declined by the server due to being unable to make correct SSL/TLS handshake (required by mutual authentication).

Please note that all configuration items starting server.* are related to an embedded Tomcat server only. You do not need it when using any standalone application server.

Spring Security for Further Client Authentication and Authorization

It would be fine to get an incoming client for our application as a logged user.

That gives us the possibility to perform some other authentications and authorizations using Spring Security (e.g. securing method calls to specific roles).

Until now, no Spring Security was needed, but all clients with any valid certificate may perform any call in our application without knowing who the caller is.

So we must configure Spring Security to create a logged user using a username from a client certificate (usually from the CN field, see the method call subjectPrincipalRegex):

@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) throws Exception {
    public UserDetailsService userDetailsService() {
        return (UserDetailsService) username -&amp;amp;amp;amp;gt; {
            if (username.equals("pavel")) {
                return new User(username, "",
            } else {
                throw new UsernameNotFoundException(String.format("User %s not found", username));

Using the bean UserDetailsService is a kind of fake, but it shows an example of an additional authentication to accept only the username "pavel".

In other words, it accepts a client with a certificate containing the value "pavel" only in the certificate's CN field (as mentioned before, configured with subjectPrincipalRegex).

As you might have noticed, only the user "pavel" is a member of the role "user", so now we are able to restrict method calls to specific roles:

    public Customer GetCustomer(@PathVariable Long id) {
        return new Customer(id, "Customer" + id);

Test Secured REST API

When you successfully import client/client_pavel.p12 into your system and the application runs, you can visit URL https://localhost:8443/customer/1.

The first access of this page displays a window to select the correct certificate to authenticate with the server: 

When you submit an incorrect certificate, you will see the "access denied" page (otherwise JSON object returned):

Thanks for reading. Originally published on

web-development web-service testing api spring-boot

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

How to Do API Testing?

API endpoint when you send the get request to that URL it returns the JSON response. In this article, I am going to use postman assertions for all the examples since it is the most popular tool. But this article is not intended only for the postman tool.

Hire Web Developer

Looking for an attractive & user-friendly web developer?, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

Wondering how to upgrade your skills in the pandemic? Here's a simple way you can do it.

Corona Virus Pandemic has brought the world to a standstill. Countries are on a major lockdown. Schools, colleges, theatres, gym, clubs, and all other public

For World Class Web Development Services in India visit RB Genie

Do you want excellent and world class web development services for your valuable projects? Contact **RB Genie **now, we have more than 8 years experienced team of web developers, which specializes in overall web design and website development...

A Simple Guide to API Development Tools

APIs can be as simple as 1 endpoint for use by 100s of users or as complex as the AWS APIs with 1000s of endpoints and 100s of thousands of users. Building them can mean spending a couple of hours using a low-code platform or months of work using a multitude of tools. Hosting them can be as simple as using one platform that does everything we need or as complex as setting up and managing ingress control, security, caching, failover, metrics, scaling.