DEV Community

Yogesh Mali
Yogesh Mali

Posted on

How to use Basic Authentication with Rest Template in Spring Boot

In this post, I will show how to use Rest Template to consume RESTful API secured with Basic Authentication. As part of this post, I will show how to build a REST API that is secured with Basic Authentication.

Overview

Basic Authentication is one of the mechanisms that you can use to secure your REST API. In my previous post, I showed how to secure REST API with Json Web Token.

Secure a REST API with Basic Authentication

Configure a REST API

Firstly, we will show a simple REST API to create users or retrieve users from the database. Then, we will secure this REST API with a Basic Authentication mechanism. Lastly, we will show how to use Basic Authentication with Rest Template to call this REST API.

Our REST controller class for this API to create or retrieve users will look like below:

package com.betterjavacode.restdemo.controllers;

import com.betterjavacode.restdemo.dto.UserDto;
import com.betterjavacode.restdemo.managers.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class UserController
{
    @Autowired
    private UserManager userManager;

    @RequestMapping(value = "/user/", method = RequestMethod.GET)
    public ResponseEntity<List<UserDto>> listAllUsers()
    {
        List<UserDto> users = userManager.getAllUsers();
        if(users.isEmpty())
        {
            return new ResponseEntity<List<UserDto>>(HttpStatus.NO_CONTENT);
        }

        return new ResponseEntity<>(users, HttpStatus.OK);
    }

    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET, produces =
            MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<UserDto> getUser(@PathVariable("id") long id)
    {
        UserDto userDto = userManager.getUser(id);
        if(userDto == null)
        {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity<>(userDto, HttpStatus.OK);
    }


    @RequestMapping(value = "/user/", method= RequestMethod.POST)
    public ResponseEntity<UserDto> createUser(@RequestBody UserDto userDto)
    {
        UserDto user = userManager.createUser(userDto);

        return new ResponseEntity<>(user, HttpStatus.OK);
    }

    @RequestMapping(value = "/user/{id}", method=RequestMethod.DELETE)
    public ResponseEntity<UserDto> deleteUser(@PathVariable("id") long id)
    {
        UserDto user = userManager.getUser(id);

        if(user == null)
        {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }

        userManager.deleteUser(id);

        return new ResponseEntity<>(HttpStatus.NO_CONTENT);
    }
}
Enter fullscreen mode Exit fullscreen mode

Our database model class for User will look like below:

package com.betterjavacode.restdemo.models;

import javax.persistence.*;
import java.io.Serializable;

@Entity(name = "User")
@Table(name = "users")
public class User implements Serializable
{
    private static final long serialVersionUID = 20200816121023L;

    public User()
    {

    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id", nullable=false)
    private long id;

    @Column(name="firstname", length=100)
    private String firstname;

    @Column(name="lastname", length=100)
    private String lastname;

    @Column(name="email", length=100)
    private String email;

    @Column(name="role", length=45)
    private String role;

    @Column(name="enabled")
    private boolean enabled;

    public long getId ()
    {
        return id;
    }

    public void setId (long id)
    {
        this.id = id;
    }

    public String getFirstname ()
    {
        return firstname;
    }

    public void setFirstname (String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname ()
    {
        return lastname;
    }

    public void setLastname (String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail ()
    {
        return email;
    }

    public void setEmail (String email)
    {
        this.email = email;
    }

    public String getRole ()
    {
        return role;
    }

    public void setRole (String role)
    {
        this.role = role;
    }

    public boolean isEnabled ()
    {
        return enabled;
    }

    public void setEnabled (boolean enabled)
    {
        this.enabled = enabled;
    }
}
Enter fullscreen mode Exit fullscreen mode

Just to make sure we understand here that, we are using a DTO object UserDto to create and retrieve the data from the database. User is our database model object.

The UserDto object will be as follows:

package com.betterjavacode.restdemo.dto;

import com.betterjavacode.restdemo.models.User;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class UserDto
{
    private String firstname;
    private String lastname;
    private String email;

    public UserDto(){}

    public UserDto(User user)
    {
        this.setEmail(user.getEmail());
        this.setFirstname(user.getFirstname());
        this.setLastname(user.getLastname());
    }

    public String getFirstname ()
    {
        return firstname;
    }

    public void setFirstname (String firstname)
    {
        this.firstname = firstname;
    }

    public String getLastname ()
    {
        return lastname;
    }

    public void setLastname (String lastname)
    {
        this.lastname = lastname;
    }

    public String getEmail ()
    {
        return email;
    }

    public void setEmail (String email)
    {
        this.email = email;
    }

}

Enter fullscreen mode Exit fullscreen mode

Once we configure our application properties and create the required database table, we will start the application.

Now if we execute the API through a client like Postman, we will be able to retrieve or create the User object.

The goal is to secure this API.

So add Spring-Security in our project build.

implementation "org.springframework.boot:spring-boot-starter-security"

Now, if we add the annotation @EnableWebSecurity in our main application class like below:

package com.betterjavacode.restdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

@SpringBootApplication
@EnableWebSecurity
public class RestdemoApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(RestdemoApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

and if we access the API to create user, we will get 401 unauthorized error like below:

Unauthorized Access of REST API

Basic Authentication

Traditionally, access to REST API will happen on the server-side once the user has logged in with authentication.

Basic authentication provides one of the ways to secure REST API. It’s not the most secure way compared to OAuth or JWT based security. In Basic Authentication, a client sends Base64 encoded credentials with each request using HTTP Authorization Header.

The client will send the Authorization header with each request. There is always a possibility of compromising these credentials even when they are Base64 encoded. To avoid that, we can use HTTPS.

Now from our implementation perspective, we will add a SecurityConfig class to configure security for our REST API.

package com.betterjavacode.restdemo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception
    {
        httpSecurity
                .csrf().disable()
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .httpBasic();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception
    {
        auth.inMemoryAuthentication()
                .withUser("adminuser")
                .password("{noop}adminpassword")
                .roles("USER");
    }
}

Enter fullscreen mode Exit fullscreen mode

configure method in this class will configure basic authentication and every request coming to our controller will need to be authorized.

configureGlobal method will add authentication of the incoming request. The requests coming through the controller will be validated for these credentials that we have configured for in-memory authentication.

WARNING – This is not the most secure way to secure your API. Definitely not with in-memory authentication. Do not use it in production.

Now if we execute REST API through POSTMAN, we will see the successful response as below:

Secure REST API with Basic Authentication

Rest Template with Basic Authentication Example

Initially, we used POSTMAN as a client to call our REST APIs. But in a real scenario, we won’t be using POSTMAN, you will have to call these APIs programmatically.

We will create a class RestClient and that will call our APIs while building Basic Authentication.

While using RestTemplate that Spring Boot provides, you need to pass HttpHeaders with a RequestEntity.

private static HttpHeaders getHeaders ()
    {
        String adminuserCredentials = "adminuser:adminpassword";
        String encodedCredentials =
                new String(Base64.encodeBase64(adminuserCredentials.getBytes()));

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "Basic " + encodedCredentials);
        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        return httpHeaders;
    }
Enter fullscreen mode Exit fullscreen mode

We use exchange method from RestTemplate to call our API and HttpHeaders that contain Basic Authentication.

The whole class RestClient will look like below:

package com.betterjavacode.restdemo;


import com.betterjavacode.restdemo.dto.UserDto;
import org.apache.tomcat.util.codec.binary.Base64;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;

public class RestClient
{
    public static final String REST_SERVICE_URL = "http://localhost:8080/user/";

    private static HttpHeaders getHeaders ()
    {
        String adminuserCredentials = "adminuser:adminpassword";
        String encodedCredentials =
                new String(Base64.encodeBase64(adminuserCredentials.getBytes()));

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Authorization", "Basic " + encodedCredentials);
        httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        return httpHeaders;
    }

    private static void listAllUsers()
    {
        System.out.println("Getting all users");
        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders httpHeaders = getHeaders();

        HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity<List> responseEntity = restTemplate.exchange(REST_SERVICE_URL,
                HttpMethod.GET, httpEntity, List.class);

        if(responseEntity.hasBody())
        {
            List<LinkedHashMap<String, Object>> users = responseEntity.getBody();

            if(users != null)
            {
                for(LinkedHashMap<String, Object> userMap: users)
                {
                    System.out.println("User is " + userMap.get("firstname") + " " + userMap.get(
                            "lastname"));
                }
            }
        }
        else
        {
            System.out.println("User not found");
        }

    }

    public static void main (String[] args)
    {
        listAllUsers();

        getUser(1);
    }



    private static void getUser(long id)
    {
        System.out.println("Getting a user ");

        String restUrl = REST_SERVICE_URL  + id;

        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders httpHeaders = getHeaders();

        HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity<String> responseEntity = restTemplate.exchange(restUrl,
                HttpMethod.GET, httpEntity, String.class);

        if(responseEntity.hasBody())
        {
            JSONObject jsonObject = new JSONObject(responseEntity.getBody());

            System.out.println(jsonObject.get("firstname"));
            System.out.println(jsonObject.get("lastname"));
        }
        else
        {
            System.out.println("User not found");
        }

    }
}
Enter fullscreen mode Exit fullscreen mode

Now if we execute the program, we will see the output as below:

Using Rest Template with Basic Authentication Response

In this post, we showed how to secure REST API with Basic Authentication. The original post was published on my blog Betterjavacode

Top comments (2)

Collapse
 
phongphamiuh profile image
phongphamiuh

Very good.

Collapse
 
mrkyaing profile image
Mg Kyaing

Thanks you sir ,
It is good .