DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How to Use Java to Build Single Sign-on
  • Develop a Secure CRUD Application Using Angular and Spring Boot
  • Configuring SSO Using WSO2 Identity Server
  • What D'Hack Is DPoP?

Trending

  • Intro to RAG: Foundations of Retrieval Augmented Generation, Part 1
  • Why High-Performance AI/ML Is Essential in Modern Cybersecurity
  • Building Enterprise-Ready Landing Zones: Beyond the Initial Setup
  • Revolutionizing Financial Monitoring: Building a Team Dashboard With OpenObserve
  1. DZone
  2. Coding
  3. Frameworks
  4. Build a Spring Boot App With Secure Server-to-Server Communication Via OAuth 2.0

Build a Spring Boot App With Secure Server-to-Server Communication Via OAuth 2.0

How to build a Spring Boot App for server-to-server communication via the OAuth 2.0 Client Credentials Grant type.

By 
Brian Demers user avatar
Brian Demers
·
Updated Jul. 08, 19 · Tutorial
Likes (17)
Comment
Save
Tweet
Share
58.3K Views

Join the DZone community and get the full member experience.

Join For Free

Most OAuth 2.0 guides are focused around the context of a user, i.e. logging in to an application using Google, Github, Okta, etc. While this can be useful, these guides ignore server-to-server communication where there is no user and you only have one service connecting to another. Thankfully, Okta is here to lend a hand with this area of application security.

The OAuth 2.0 Client Credentials Grant type is exclusively used for scenarios in which no user exists (CRON jobs, scheduled tasks, other data workloads, etc.). This flow is less showy than other OAuth flows as there is no end user or browser. However, this is far easier to understand than the more complicated, user-centric OAuth 2.0 grant types. In this tutorial, we'll walk through the OAuth 2.0 Client Credentials Grant type and how you can deploy it for secure server-to-server communication in Spring Boot.

OAuth 2.0 Client Credentials Grant

The goal of the Client Credentials Grant is to allow two machines to communicate securely. In this grant type, you have a client (think of this as your application) making API requests to another service (this is your resource server).

To help illustrate why this flow is important, let’s take a step back and talk about what we did before OAuth 2.0.

NOTE: If you’re an OAuth pro, you can skip ahead to the code examples below or check out this example on GitHub.

Before OAuth 2.0, the way developers handled server-to-server authentication was with HTTP Basic Auth. Essentially, this boiled down to a developer that would send over a server’s unique username and password (often referred to as an ID and secret) on each request. The API service would then validate this username and password on every request by connecting to a user store (database, LDAP, etc.) in order to validate the credentials.

Password sequence diagram

This approach has a few drawbacks and exposure points:

  • Each application in the diagram above handles the username and password.
  • A second username and password might be needed to connect to the user store.
  • The same username and password is used for each request.

There are various ways to help mitigate these risks, but that’s out of scope in this post.

The OAuth 2.0 Client Credentials Grant was created to help solve the problems that originated with HTTP Basic Auth. While the client still uses a username and password (called the client_id and client_secret), instead of sending them directly to the API service on each request, they are instead exchanged for a token via an authorization server.

Client credentials sequence diagram

The authorization server returns a temporary access token (which is used until it expires). The client then uses this access token when communicating with the resource server, which means that your client’s most sensitive data (the ID and secret) are only shared over the network once every expiration period, dramatically reducing the likelihood of compromise. Once the resource server receives the incoming request with the access token, it will then validate the token with by talking to the authorization server.

I’ll talk about a couple of ways to reduce the number of network calls further at the end of this post, but, first, onto an example!

Let’s Build an OAuth 2.0 Client Credentials App!

Enough talk, let’s do something! I’m going to show you how to implement the Client Credentials Grant type with Spring using two applications: a client and server. The server will have a single endpoint which returns a “message of the day.” The client will be a simple command line application; you could easily replace this with a backend web application, CRON job, or any other backend script.

Set Up Your Authorization Server

To keep things simple, you’ll use Okta to create an OAuth 2.0 authorization server. This will handle all of the Client Credentials Grant stuff mentioned above. Do you need to use Okta? Not at all! You can use any OAuth 2.0 compatible server that you want. But, because our service is free and simple to use, it speeds up this process.

If you don’t already have a free developer account, head over to developer.okta.com and click Sign Up. When that’s complete, you’ll have two pieces of information, your Okta base URL, which looks something like: dev-123456.oktapreview.com, and an email with instructions on how to activate your account.

After activating your account, while you are still in the Okta Developer Console, you then need to create an application and a custom OAuth scope. The application will give you a client ID and secret, while the custom scope will restrict your access token to this example.

Click the Applications menu item, then Add Application.  Next, select Service -> Next. You will then change the name to whatever you want (I’m going to use “My MOD App”). Next, click Done.

You will need the Client ID and Client secret values for the next steps.

Then, create a custom scope for your application.

From the menu bar, select API -> Authorization Servers. Remember the Issuer URI value; you will need this for the following steps. Edit the authorization server by clicking on the edit pencil, then click Scopes -> Add Scope. Fill out the name field with custom_mod and press Create.

Create a custom scope in Okta Developer Console

Now, onto the fun stuff!

Create a Resource Server

This resource server (aka: API service) is going to be overly simple and consist of a single /mod endpoint. Now, create a new project using the Spring Initializer on the command line:

curl https://start.spring.io/starter.tgz  \
  -d artifactId=creds-example-server \
  -d dependencies=security,web \
  -d language=java \
  -d type=maven-project \
  -d baseDir=creds-example-server \
| tar -xzvf -

# change into the new directory
cd creds-example-server


You will also need to manually add one more dependency to your pom.xml:

<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>


NOTE: I also renamed the DemoApplication to ServerApplication , because we are going to create another application shortly.

Next, update the ServerApplication to include the @EnableResourceServer annotation and add a simple REST controller:

@EnableResourceServer
@SpringBootApplication
public class ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerApplication.class, args);
    }

    /**
     * Allows for @PreAuthorize annotation processing.
     */
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
        @Override
        protected MethodSecurityExpressionHandler createExpressionHandler() {
            return new OAuth2MethodSecurityExpressionHandler();
        }
    }

    @RestController
    public class MessageOfTheDayController {
        @GetMapping("/mod")
        @PreAuthorize("#oauth2.hasScope('custom_mod')")
        public String getMessageOfTheDay(Principal principal) {
            return "The message of the day is boring for user: " + principal.getName();
        }
    }
}


Now it is time to configure the application! I renamed my application.properties file to application.yml and updated it to include:

security:
  oauth2:
    client:
      clientId: {client-id-from-above}
      clientSecret: {client-secret-from-above}
    resource:
      tokenInfoUri: {issuer-uri-from-above}/v1/introspect


That’s it! Just a few lines of code and a couple lines of config! Spring Boot will automatically handle the validation of the access tokens — all you need to do now is worry about is your code!

Next, start it up and leave it running:

./mvn spring-boot:run


You can try to access http://localhost:8080/mod , if you want. It will respond with HTTP 401 UNAUTHORIZED.

Create the OAuth 2.0 Client

Next, you’re going to create a simple command-line client (you could easily duplicate this logic in any type of application).

Next, open up a new terminal window and create a second application with the Spring Initializer:

curl https://start.spring.io/starter.tgz  \
  -d artifactId=creds-example-client \
  -d dependencies=security \
  -d language=java \
  -d type=maven-project \
  -d baseDir=creds-example-client \
| tar -xzvf -

# change into the new directory
cd creds-example-client


This will follow the same instructions as before — add in the Spring OAuth 2.0 library as a dependency in your pom.xml:

<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>


This time, I’ll start by defining the configuration (again I renamed application.properties to application.yml):

example:
  baseUrl: http://localhost:8080
  oauth2:
    client:
      grantType: client_credentials
      clientId: {client-id-from-above}
      clientSecret: {client-secret-from-above}
      accessTokenUri: {issuer-uri-from-above}/v1/token
      scope: custom_mod


I’ve namespaced the configuration under example since you could be connecting to multiple servers.

I configured a few properties:

  • baseUrl is the base URL of our example server
  • grantType defines the grant type for the connection
  • clientId and clientSecret are the same as above
  • accessTokenUri defines the URI used to get an access token
  • scope is the custom scope we created above

Last up is our ClientApplication (renamed from DemoApplication):

@SpringBootApplication
public class ClientApplication implements CommandLineRunner {

    private final Logger logger = LoggerFactory.getLogger(ClientApplication.class);

    @Value("#{ @environment['example.baseUrl'] }")
    private String serverBaseUrl;

    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }

    @Bean
    @ConfigurationProperties("example.oauth2.client")
    protected ClientCredentialsResourceDetails oAuthDetails() {
        return new ClientCredentialsResourceDetails();
    }

    @Bean
    protected RestTemplate restTemplate() {
        return new OAuth2RestTemplate(oAuthDetails());
    }

    @Override
    public void run(String... args) {
        logger.info("MOD: {}", restTemplate().getForObject(serverBaseUrl + "/mod", String.class));
    }
}


There are a few items that I want to touch on:

  • The CommandLineRunner interface adds a run method, which is called automatically after initialization. The application exits after leaving this method.
  • I created an ClientCredentialsResourceDetails bean, which is bound to my configuration properties: example.oauth2.client . 
  • I used an OAuth2RestTemplate in place of a standard RestTemplate . This automatically manages all of the OAuth 2.0 access token exchange and sets the Authentication: Bearer header value. Basically, it handles all of the OAuth detail so you don’t need to worry about any of them!

Next, run the application with ./mvnw spring-boot:run and you should see a console output similar to:

2018-03-20 12:56:10.058  INFO 15833 --- [main] c.e.c.ClientApplication: MOD: The message of the day is boring for user: 0oabcd12yz2EpHuis75s3

The client has successfully communicated with the server! Not bad, right? In just a few lines of code, you were able to get an OAuth 2.0 authorization server setup and configured, as well as create two Spring apps (one client and one server) that can now communicate securely using the OAuth 2.0 Client Credentials Grant type!

NOTE: if you see a 401 or 500 exception, double check that your application.yml config files contain the correct information.

Extra Credit: Reduce the Number of Calls to the Authorization Server

The second sequence diagram above seems more complicated than the first, even when factoring in the reuse of an access token. Access tokens are opaque. There is no spec behind them, and the format is left to the implementation of the authorization server.

At Okta, we use signed JWTs, which means you can validate them locally, instead of making an additional request from the API service to the authorization server on each request.

Client credentials with JWT sequence

We have helper libraries in a few different languages and a Spring Boot starter that will handle the local validation for you.

NOTE: at the time of this writing, okta-spring-boot only works with Spring Boot 1.5.x. You can see an example on GitHub.

Learn More About OAuth 2.0 and Okta

In this post, I’ve explained the OAuth 2.0 Client Credentials Grant type and created small demo applications that exercised this flow (with very little code, thanks to Spring Boot!). If you have questions, leave them below or ping me (@briandemers) or @OktaDev on Twitter.

For more info on OAuth 2.0 and Okta, check out these resources:

  • What the Heck is OAuth?
  • OAuth.com
  • Secure your SPA with Spring Boot and OAuth

Secure Server-to-Server Communication with Spring Boot and OAuth 2.0 was originally published on the Okta developer blog on April 2, 2018.

Spring Framework authentication security Spring Boot application app Build (game engine)

Published at DZone with permission of Brian Demers, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How to Use Java to Build Single Sign-on
  • Develop a Secure CRUD Application Using Angular and Spring Boot
  • Configuring SSO Using WSO2 Identity Server
  • What D'Hack Is DPoP?

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!