Spring Security - JWT Authentication - Series 1
- Anand Nerurkar
- Apr 4, 2022
- 5 min read
Updated: Apr 10, 2022
Let us create a REST API & access endpoint with JWT token, please follow below steps for your reference. Here we will make use of plain text based password for simplicity and making use of hardcoded username and password for keeping it simple.
Prerequisite Knowledge
Spring Boot
Java 8
Maven
Spring Security
Spring Starter https://start.spring.io/
Eclipse IDE
Tutorial codebase - https://github.com/anerurkar/jwt-demo/tree/master
1. Use spring starter to create spring boot project and mention the required dependency.

2. Click on generate.
project will be generated and downloaded to your local disk in the form of zip
unzip the project & import project into eclipse
3. Select project and run maven install
It should build successfully and can see default password generated since we have
included spring security in class path.
-------------server console log sample start ---------------
2022-04-04 10:31:59.160 WARN 4332 --- [ main] .s.s.UserDetailsServiceAutoConfiguration :
Using generated security password: bfd8810c-2439-4f0d-8fe1-92eadf4a3794
This generated password is for development use only. Your security configuration must be updated before running your application in production.
2022-04-04 10:31:59.376 INFO 4332 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will not secure any request
-----------server console log sample end-----------
4. Let us create model,controller,service & config package

5. Let us create UserService that make use of spring UserDetailsService for authentication
purpose. Currently we will hardcode user for simplicity. Please see below code sample
--------------UserService Sample--------
/**
*
*/
package com.techbytes.jwtdemo.service;
import java.util.ArrayList;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
* @author andyn
*
*/
@Service
public class UserService implements UserDetailsService {
/**
*
*/
public UserService() {
// TODO Auto-generated constructor stub
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// TODO Auto-generated method stub
/*
* logic to get the user from database
* User user=userRepository.findByUsername(username);
* return spring user as below with username,password and granted authority
* return new User(user.getUsername(),user.getPassword(),new ArrayList<T>());
*/
/*
* currently we are hardcoding the user as below
*/
return new User("admin","password",new ArrayList());
}
}
6. Let us create securityconfiguration
Securityconfiguration extend webSecurityConfigurerAdapter
Autowire userservice for authentication.
Override configure(AuthenticationManagerBuilder )
Annotate class with @EnableWebSecurity,@configuration
As we are using simple text based password and by default spring does encrypt password, we need to instruct spring for plain password, so we make use of noopspasswordencoder bean in main class as below
------------JWTDemoApplication-Main class--------
====
package com.techbytes.jwtdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@SpringBootApplication
public class JwtDemoApplication {
public static void main(String[] args) {
SpringApplication.run(JwtDemoApplication.class, args);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
---------------SecurityConfiguration-------------------
/**
*
*/
package com.techbytes.jwtdemo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import com.techbytes.jwtdemo.service.UserService;
/**
* @author andyn
*
*/
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
/**
*
*/
@Autowired
UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
}
7. Let us create sample controller
/**
*
*/
package com.techbytes.jwtdemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author andyn
*
*/
@RestController
@RequestMapping("/api")
public class SampleConroller {
@GetMapping("/sample")
public String welcome() {
return "Welcome To JWT Authentication-Text Based Password";
}
}
add below entry in resources/application.yml
server:
port: 9092
servlet:
context-path: /api
7. Build & Run
Select your project, run maven install, this will build your project successfully.
Select JwtDemoApplication & run Java application
Hit http://localhost:9092/api/sample in browser
Since security is enabled ,spring security open http basic form and will redirect you to

please enter hardcoded username as admin , password as password and click submit.
Your endpoint will /sample will return response as below.

Till this step we have seen how spring security with basic form work.
8. Now we will proceed further for JWT authentication.
Please include below dependency in pom.xml file
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
9. Create JWTUtility class that will take care of generating token,validating token.
-----------------JWTUtility-----------------------
package com.techbytes.jwtdemo.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JWTUtility implements Serializable {
private static final long serialVersionUID = 234234523523L;
public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60;
@Value("${jwt.secret}")
private String secretKey;
//get username from jwt token
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
//get expiration date from jwt token
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
//for fetching any information from token we will need the secret key
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody();
}
//check if the token has expired
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
//generate token for user
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
/*
* while creating the token -
* Define claims of the token - Issuer, Expiration, Subject, and the ID
Sign the JWT using the HS512 algorithm and secret key
*/
private String doGenerateToken(Map<String, Object> claims, String subject) {
return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, secretKey).compact();
}
//validate token
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
}
10. Let us create one endpoint /authenticate with jwtreq, jwtresp object in sample controller
@PostMapping("/authenticate")
public JwtResp authenticate(@RequestBody JwtReq jwtReq) throws Exception{
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
jwtReq.getUserName(),
jwtReq.getPassword()
)
);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
// fetch user from userservice to get userdetails
final UserDetails userDetails
= userService.loadUserByUsername(jwtReq.getUserName());
// generate jwttoken with username
final String token =
jwtUtility.generateToken(userDetails);
return new JwtResp(token);
}
-------------------------JWTReq----------------
/**
*
*/
package com.techbytes.jwtdemo.model;
import java.io.Serializable;
/**
* @author andyn
*
*/
public class JwtReq implements Serializable {
String userName;
String password;
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
public JwtReq(String userName, String password) {
super();
this.userName = userName;
this.password = password;
}
public JwtReq() {
super();
}
}
---------------------------JWTResp-----------------
/**
*
*/
package com.techbytes.jwtdemo.model;
import java.io.Serializable;
/**
* @author andyn
*
*/
public class JwtResp implements Serializable {
String jwtToken;
public JwtResp() {
super();
// TODO Auto-generated constructor stub
}
public JwtResp(String jwtToken) {
super();
this.jwtToken = jwtToken;
}
/**
* @return the jwtToken
*/
public String getJwtToken() {
return jwtToken;
}
/**
* @param jwtToken the jwtToken to set
*/
public void setJwtToken(String jwtToken) {
this.jwtToken = jwtToken;
}
}
11. update security configuration class with below bean
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
12. Add below property in resources/application.yml
jwt
secret: secretkey123
we need to make sure that /authenticate should be permitted and rest endpoint should be authenticated. So please include below method in securityconfiguration class.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/authenticate")
.permitAll()
.anyRequest()
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
}
13. Build the project and run application.
Let us open the request in postman and will hit /api/sample endpoint.
You should get 403- forbidden

Now we will generate token with /authenticate endpoint in postman with required details as shown below to generate token.

Now hit /api/sample without token, will receive 403 status code

Now hit /api/sample with token, as mentioned in below screenshot. You will receive response.

Comments