Quick and Dirty way to add User authentication in Spring Boot Back-end

Yo Han Joo
3 min readJul 7, 2021

--

So I’ve been always fascinated with user authentication in web applications and it also seems like the bread and butter of apps. Even the use of jwt seems to be a requirement. In this tutorial, I will show you a quick and dirty way to add a jwt user authentication to spring boot.

First off, let’s list all of the required dependencies to our project’s pom.xml:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

Next, let’s add a User model:

@Document
public class User {

@Id
private String id;

private String username;

private String email;

private int role;

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;

public User() {
}

public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.role = 0;
this.password = password;
}

... getters, setters, toString
}

The password has JsonProperty WRITE_ONLY as we don’t want to display the field to the user if they request details!

Let’s add the repository interface:

@Repository
public interface UserRepository extends MongoRepository<User, String> {
Optional<User> findUserByUsername(String username);
Optional<User> findUserByEmail(String email);
}

This is the repository we will use. There is not much explanation to be done here so let’s continue, which is the service side:

@Service
public class UserService {

@Value("${SECRET_KEY}")
private String secret;
private final PasswordEncoder passwordEncoder;
private final UserRepository userRepository;

/**
* Constructor
*/
@Autowired
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}

/**
* User registration
*/
public String createUser(User user) {
if(userRepository.findUserByEmail(user.getEmail()).isPresent())
throw new IllegalStateException("email taken");
if(userRepository.findUserByUsername(user.getUsername()).isPresent())
throw new IllegalStateException("username taken");

user.setPassword(passwordEncoder.encode(user.getPassword()));

userRepository.save(user);
return "success";
}

/**
* User Login
*/
public String loginUser(User requestUser) {
User user = userRepository.findUserByUsername(requestUser.getUsername()).orElseThrow(() -> new IllegalStateException("User with that username does not exist"));

if(passwordEncoder.matches(requestUser.getPassword(), user.getPassword())) {
return Jwts.builder()
.setSubject(user.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 1800000))
.signWith(SignatureAlgorithm.HS256, secret.getBytes(StandardCharsets.UTF_8))
.compact();
} else {
throw new IllegalStateException("invalid password");
}
}

/**
* Returns username if jwt is valid
*/
public String validateUser(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(secret.getBytes(StandardCharsets.UTF_8))
.parseClaimsJws(jwt).getBody();

return claims.getSubject();
}
}

Ok, there is much to talk about here. Let’s start with the variables first:

We will need to import a secret key from our application.properties. We will also need our user repository and the password encoder (for jwt).

Next let’s go to the registerUser function:

public String createUser(User user) {
if(userRepository.findUserByEmail(user.getEmail()).isPresent())
throw new IllegalStateException("email taken");
if(userRepository.findUserByUsername(user.getUsername()).isPresent())
throw new IllegalStateException("username taken");

user.setPassword(passwordEncoder.encode(user.getPassword()));

userRepository.save(user);
return "success";
}

The registration function first checks if the user email or username is already taken, otherwise it hashes the password. The login user is pretty self explanatory.

public String loginUser(User requestUser) {
User user = userRepository.findUserByUsername(requestUser.getUsername()).orElseThrow(() -> new IllegalStateException("User with that username does not exist"));

if(passwordEncoder.matches(requestUser.getPassword(), user.getPassword())) {
return Jwts.builder()
.setSubject(user.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + 1800000))
.signWith(SignatureAlgorithm.HS256, secret.getBytes(StandardCharsets.UTF_8))
.compact();
} else {
throw new IllegalStateException("invalid password");
}
}

In this function, it first searches if the user exists. then the passwordEncoder compares the requested password and the password in the database. if it matches, the function will return a Jwt.

public String validateUser(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(secret.getBytes(StandardCharsets.UTF_8))
.parseClaimsJws(jwt).getBody();

return claims.getSubject();
}

The validate user checks the jwt that is sent from the user later on.

Now the only thing that’s left is our controller.

@RestController
@RequestMapping(path = "/api/v1/users")
public class UserController {

private final UserService userService;

@Autowired
public UserController(UserService userService) {
this.userService = userService;
}

@PostMapping("/register")
public String createUser(@RequestBody User user) {
return userService.createUser(user);
}

@PostMapping("/login")
public String loginUser(@RequestBody User user) {
return userService.loginUser(user);
}

@GetMapping("/validate")
public String validateUser(@RequestHeader("Bearer") String jwt) {
return userService.validateUser(jwt);
}
}

Because userService handles everything for us, the controller is pretty lightweight.

Now we are done! Check out your application and it should be up and running :)

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Yo Han Joo
Yo Han Joo

Written by Yo Han Joo

I am a student at KTH, Computer Engineering

No responses yet

Write a response