diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
index bf0f243..3434190 100644
--- a/.github/workflows/package.yml
+++ b/.github/workflows/package.yml
@@ -26,7 +26,7 @@ jobs:
uses: actions/setup-java@v2
with:
java-version: 17
- distribution: 'zulu'
+ distribution: 'adopt'
- name: Build with Maven
run: mvn clean install -DENV_VAR=${{ env.ENV_VAR }}
@@ -35,7 +35,7 @@ jobs:
run: mvn -B package --file pom.xml
- name: Upload WAR file as artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ECD-API
path: target/ecdapi.war
diff --git a/pom.xml b/pom.xml
index d9a982d..2d0d9fb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,25 +28,21 @@
1.2.0.Final
-
+
org.springframework.boot
spring-boot-starter-aop
3.2.2
-
- co.elastic.logging
- logback-ecs-encoder
- 1.3.2
+
+ co.elastic.logging
+ logback-ecs-encoder
+ 1.3.2
-
+
org.slf4j
slf4j-api
@@ -101,8 +97,7 @@
8.2.0
-
+
jakarta.persistence
jakarta.persistence-api
@@ -169,15 +164,14 @@
org.apache.poi
poi-ooxml
5.2.5
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
org.springframework.boot
spring-boot-starter-data-redis
@@ -219,8 +213,7 @@
jackson-datatype-joda
2.17.0
-
+
com.fasterxml.jackson.core
jackson-databind
@@ -232,6 +225,26 @@
jackson-core
2.17.0-rc1
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.12.6
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.12.6
+ runtime
+
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.12.6
+ runtime
+
@@ -315,8 +328,7 @@
${target-properties} and
${source-properties}
-
diff --git a/src/main/environment/ecd_ci.properties b/src/main/environment/ecd_ci.properties
index afc45ca..dfcfdb0 100644
--- a/src/main/environment/ecd_ci.properties
+++ b/src/main/environment/ecd_ci.properties
@@ -14,10 +14,17 @@ secondary.datasource.driver-class-name=com.mysql.jdbc.Driver
registerBeneficiaryUrl=@env.COMMON_API@/beneficiary/create
##Beneficiary Edit Url
+
+beneficiaryEditUrl =@env.COMMON_API_BASE_URL@/beneficiary/update
+jwt.secret=@env.JWT_SECRET_KEY@
+
beneficiaryEditUrl =@env.COMMON_API@/beneficiary/update
+
#ELK logging file name
logging.file.name=@env.ECD_API_LOGGING_FILE_NAME@
+
springdoc.api-docs.enabled=false
-springdoc.swagger-ui.enabled=false
\ No newline at end of file
+springdoc.swagger-ui.enabled=false
+
diff --git a/src/main/environment/ecd_dev.properties b/src/main/environment/ecd_dev.properties
index e668931..779e08f 100644
--- a/src/main/environment/ecd_dev.properties
+++ b/src/main/environment/ecd_dev.properties
@@ -16,5 +16,9 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia
##Beneficiary Edit Url
beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update
+jwt.secret=
+
+
springdoc.api-docs.enabled=true
-springdoc.swagger-ui.enabled=true
\ No newline at end of file
+springdoc.swagger-ui.enabled=true
+
diff --git a/src/main/environment/ecd_test.properties b/src/main/environment/ecd_test.properties
index e668931..779e08f 100644
--- a/src/main/environment/ecd_test.properties
+++ b/src/main/environment/ecd_test.properties
@@ -16,5 +16,9 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia
##Beneficiary Edit Url
beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update
+jwt.secret=
+
+
springdoc.api-docs.enabled=true
-springdoc.swagger-ui.enabled=true
\ No newline at end of file
+springdoc.swagger-ui.enabled=true
+
diff --git a/src/main/environment/ecd_uat.properties b/src/main/environment/ecd_uat.properties
index e668931..779e08f 100644
--- a/src/main/environment/ecd_uat.properties
+++ b/src/main/environment/ecd_uat.properties
@@ -16,5 +16,9 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia
##Beneficiary Edit Url
beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update
+jwt.secret=
+
+
springdoc.api-docs.enabled=true
-springdoc.swagger-ui.enabled=true
\ No newline at end of file
+springdoc.swagger-ui.enabled=true
+
diff --git a/src/main/java/com/iemr/ecd/EcdApiApplication.java b/src/main/java/com/iemr/ecd/EcdApiApplication.java
index fcba632..5a7f6e7 100644
--- a/src/main/java/com/iemr/ecd/EcdApiApplication.java
+++ b/src/main/java/com/iemr/ecd/EcdApiApplication.java
@@ -24,6 +24,13 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import com.iemr.ecd.dao.Users;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Contact;
@@ -37,4 +44,19 @@ public static void main(String[] args) {
SpringApplication.run(EcdApiApplication.class, args);
}
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(factory);
+
+ // Use StringRedisSerializer for keys (userId)
+ template.setKeySerializer(new StringRedisSerializer());
+
+ // Use Jackson2JsonRedisSerializer for values (Users objects)
+ Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Users.class);
+ template.setValueSerializer(serializer);
+
+ return template;
+ }
+
}
diff --git a/src/main/java/com/iemr/ecd/config/RedisConfig.java b/src/main/java/com/iemr/ecd/config/RedisConfig.java
index 22818fa..58cd150 100644
--- a/src/main/java/com/iemr/ecd/config/RedisConfig.java
+++ b/src/main/java/com/iemr/ecd/config/RedisConfig.java
@@ -22,11 +22,19 @@
package com.iemr.ecd.config;
import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import com.iemr.ecd.dao.Users;
@Configuration
+@EnableCaching
public class RedisConfig {
private @Value("${spring.redis.host}") String redisHost;
@@ -37,4 +45,19 @@ LettuceConnectionFactory lettuceConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(factory);
+
+ // Use StringRedisSerializer for keys (userId)
+ template.setKeySerializer(new StringRedisSerializer());
+
+ // Use Jackson2JsonRedisSerializer for values (Users objects)
+ Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Users.class);
+ template.setValueSerializer(serializer);
+
+ return template;
+ }
+
}
diff --git a/src/main/java/com/iemr/ecd/dao/Users.java b/src/main/java/com/iemr/ecd/dao/Users.java
new file mode 100644
index 0000000..97c9118
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/dao/Users.java
@@ -0,0 +1,103 @@
+package com.iemr.ecd.dao;
+
+import java.io.Serializable;
+import java.sql.Timestamp;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.google.gson.annotations.Expose;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.Data;
+
+@Data
+@Entity
+@Table(name = "m_user")
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Users implements Serializable {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Expose
+ @Column(name = "UserID")
+ private Long userID;
+ @Expose
+ @Column(name = "TitleID") private Short titleID;
+ @Expose
+ @Column(name = "FirstName")
+ private String firstName;
+ @Expose
+ @Column(name = "MiddleName")
+ private String middleName;
+ @Expose
+ @Column(name = "lastName")
+ private String lastName;
+ @Expose
+ @Column(name = "GenderID")
+ private Short genderID;
+ @Expose
+ @Column(name = "MaritalStatusID")
+ private Short maritalStatusID;
+ @Expose
+ @Column(name = "AadhaarNo")
+ private String aadhaarNo;
+ @Expose
+ @Column(name = "PAN")
+ private String pan;
+ @Expose
+ @Column(name = "DOB")
+ private Timestamp dob;
+ @Expose
+ @Column(name = "DOJ")
+ private Timestamp doj;
+ @Expose
+ @Column(name = "QualificationID")
+ private Integer qualificationID;
+ @Expose
+ @Column(name = "UserName")
+ private String userName;
+ @Expose
+ @Column(name = "Password")
+ private String password;
+ @Expose
+ @Column(name = "AgentID")
+ private String agentID;
+ @Expose
+ @Column(name = "AgentPassword")
+ private String agentPassword;
+ @Expose
+ @Column(name = "EmailID")
+ private String emailID;
+ @Expose
+ @Column(name = "StatusID")
+ private Short statusID;
+ @Expose
+ @Column(name = "EmergencyContactPerson")
+ private String emergencyContactPerson;
+ @Expose
+ @Column(name = "EmergencyContactNo")
+ private String emergencyContactNo;
+ @Expose
+ @Column(name = "IsSupervisor")
+ private Boolean isSupervisor;
+ @Expose
+ @Column(name = "Deleted")
+ private Boolean deleted;
+ @Expose
+ @Column(name = "CreatedBy")
+ private String createdBy;
+ @Expose
+ @Column(name = "CreatedDate")
+ private Timestamp createdDate;
+ @Expose
+ @Column(name = "ModifiedBy")
+ private String modifiedBy;
+ @Expose
+ @Column(name = "LastModDate")
+ private Timestamp lastModDate;
+
+}
+
diff --git a/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java
new file mode 100644
index 0000000..bae8d1e
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java
@@ -0,0 +1,16 @@
+package com.iemr.ecd.repository.ecd;
+
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import com.iemr.ecd.dao.Users;
+
+@Repository
+public interface UserLoginRepo extends CrudRepository {
+
+ @Query(" SELECT u FROM Users u WHERE u.userID = :userID AND u.deleted = false ")
+ public Users getUserByUserID(@Param("userID") Long userID);
+
+}
diff --git a/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java
new file mode 100644
index 0000000..d0c24c1
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java
@@ -0,0 +1,31 @@
+package com.iemr.ecd.utils.mapper;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Service
+public class CookieUtil {
+
+ public Optional getCookieValue(HttpServletRequest request, String cookieName) {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ if (cookieName.equals(cookie.getName())) {
+ return Optional.of(cookie.getValue());
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ public String getJwtTokenFromCookie(HttpServletRequest request) {
+ return Arrays.stream(request.getCookies()).filter(cookie -> "Jwttoken".equals(cookie.getName()))
+ .map(Cookie::getValue).findFirst().orElse(null);
+ }
+}
diff --git a/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java b/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java
new file mode 100644
index 0000000..98867f8
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java
@@ -0,0 +1,19 @@
+package com.iemr.ecd.utils.mapper;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class FilterConfig {
+
+ @Bean
+ public FilterRegistrationBean jwtUserIdValidationFilter(
+ JwtAuthenticationUtil jwtAuthenticationUtil) {
+ FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
+ registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil));
+ registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints
+ return registrationBean;
+ }
+
+}
diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java
new file mode 100644
index 0000000..e72b50a
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java
@@ -0,0 +1,126 @@
+package com.iemr.ecd.utils.mapper;
+
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+
+import com.iemr.ecd.dao.Users;
+import com.iemr.ecd.repository.ecd.UserLoginRepo;
+import com.iemr.ecd.utils.advice.exception_handler.ECDException;
+
+import io.jsonwebtoken.Claims;
+import jakarta.servlet.http.HttpServletRequest;
+
+@Component
+public class JwtAuthenticationUtil {
+
+ @Autowired
+ private CookieUtil cookieUtil;
+ @Autowired
+ private JwtUtil jwtUtil;
+ @Autowired
+ private RedisTemplate redisTemplate;
+ @Autowired
+ private UserLoginRepo userLoginRepo;
+ private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) {
+ this.cookieUtil = cookieUtil;
+ this.jwtUtil = jwtUtil;
+ }
+
+ public ResponseEntity validateJwtToken(HttpServletRequest request) {
+ Optional jwtTokenOpt = cookieUtil.getCookieValue(request, "Jwttoken");
+
+ if (jwtTokenOpt.isEmpty()) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body("Error 401: Unauthorized - JWT Token is not set!");
+ }
+
+ String jwtToken = jwtTokenOpt.get();
+
+ // Validate the token
+ Claims claims = jwtUtil.validateToken(jwtToken);
+ if (claims == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Invalid JWT Token!");
+ }
+
+ // Extract username from token
+ String usernameFromToken = claims.getSubject();
+ if (usernameFromToken == null || usernameFromToken.isEmpty()) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
+ .body("Error 401: Unauthorized - Username is missing!");
+ }
+
+ // Return the username if valid
+ return ResponseEntity.ok(usernameFromToken);
+ }
+
+ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception {
+ try {
+ // Validate JWT token and extract claims
+ Claims claims = jwtUtil.validateToken(jwtToken);
+
+ if (claims == null) {
+ throw new ECDException("Invalid JWT token.");
+ }
+
+ String userId = claims.get("userId", String.class);
+
+ // Check if user data is present in Redis
+ Users user = getUserFromCache(userId);
+ if (user == null) {
+ // If not in Redis, fetch from DB and cache the result
+ user = fetchUserFromDB(userId);
+ }
+ if (user == null) {
+ throw new Exception("Invalid User ID.");
+ }
+
+ return true; // Valid userId and JWT token
+ } catch (Exception e) {
+ logger.error("Validation failed: " + e.getMessage(), e);
+ throw new Exception("Validation error: " + e.getMessage(), e);
+ }
+ }
+
+ private Users getUserFromCache(String userId) {
+ String redisKey = "user_" + userId; // The Redis key format
+ Users user = (Users) redisTemplate.opsForValue().get(redisKey);
+
+ if (user == null) {
+ logger.warn("User not found in Redis. Will try to fetch from DB.");
+ } else {
+ logger.info("User fetched successfully from Redis.");
+ }
+
+ return user; // Returns null if not found
+ }
+
+ private Users fetchUserFromDB(String userId) {
+ // This method will only be called if the user is not found in Redis.
+ String redisKey = "user_" + userId; // Redis key format
+
+ // Fetch user from DB
+ Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId));
+
+ if (user != null) {
+ // Cache the user in Redis for future requests (cache for 30 minutes)
+ redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES);
+
+ // Log that the user has been stored in Redis
+ logger.info("User stored in Redis with key: " + redisKey);
+ } else {
+ logger.warn("User not found for userId: " + userId);
+ }
+
+ return user;
+ }
+}
diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java
new file mode 100644
index 0000000..d7d1c09
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java
@@ -0,0 +1,111 @@
+package com.iemr.ecd.utils.mapper;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Component
+public class JwtUserIdValidationFilter implements Filter {
+
+ private final JwtAuthenticationUtil jwtAuthenticationUtil;
+ private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) {
+ this.jwtAuthenticationUtil = jwtAuthenticationUtil;
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+ String path = request.getRequestURI();
+ String contextPath = request.getContextPath();
+ logger.info("JwtUserIdValidationFilter invoked for path: " + path);
+
+ // Log cookies for debugging
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ if ("userId".equals(cookie.getName())) {
+ logger.warn("userId found in cookies! Clearing it...");
+ clearUserIdCookie(response); // Explicitly remove userId cookie
+ }
+ }
+ } else {
+ logger.info("No cookies found in the request");
+ }
+
+ // Log headers for debugging
+ String jwtTokenFromHeader = request.getHeader("Jwttoken");
+ logger.info("JWT token from header: ");
+
+ // Skip login and public endpoints
+ if (path.equals(contextPath + "/user/userAuthenticate")
+ || path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession")
+ || path.startsWith(contextPath + "/public")) {
+ logger.info("Skipping filter for path: " + path);
+ filterChain.doFilter(servletRequest, servletResponse);
+ return;
+ }
+
+ try {
+ // Retrieve JWT token from cookies
+ String jwtTokenFromCookie = getJwtTokenFromCookies(request);
+ logger.info("JWT token from cookie: ");
+
+ // Determine which token (cookie or header) to validate
+ String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader;
+ if (jwtToken == null) {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers");
+ return;
+ }
+
+ // Validate JWT token and userId
+ boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken);
+
+ if (isValid) {
+ // If token is valid, allow the request to proceed
+ filterChain.doFilter(servletRequest, servletResponse);
+ } else {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token");
+ }
+ } catch (Exception e) {
+ logger.error("Authorization error: ", e);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage());
+ }
+ }
+
+ private String getJwtTokenFromCookies(HttpServletRequest request) {
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().equals("Jwttoken")) {
+ return cookie.getValue();
+ }
+ }
+ }
+ return null;
+ }
+
+ private void clearUserIdCookie(HttpServletResponse response) {
+ Cookie cookie = new Cookie("userId", null);
+ cookie.setPath("/");
+ cookie.setHttpOnly(true);
+ cookie.setSecure(true);
+ cookie.setMaxAge(0); // Invalidate the cookie
+ response.addCookie(cookie);
+ }
+}
diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java
new file mode 100644
index 0000000..18630d8
--- /dev/null
+++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java
@@ -0,0 +1,63 @@
+package com.iemr.ecd.utils.mapper;
+
+import java.security.Key;
+import java.util.Date;
+import java.util.function.Function;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+
+@Component
+public class JwtUtil {
+
+ @Value("${jwt.secret}")
+ private String SECRET_KEY;
+
+ private static final long EXPIRATION_TIME = 24L * 60 * 60 * 1000; // 1 day in milliseconds
+
+ // Generate a key using the secret
+ private Key getSigningKey() {
+ if (SECRET_KEY == null || SECRET_KEY.isEmpty()) {
+ throw new IllegalStateException("JWT secret key is not set in application.properties");
+ }
+ return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
+ }
+
+ // Generate JWT Token
+ public String generateToken(String username, String userId) {
+ Date now = new Date();
+ Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);
+
+ // Include the userId in the JWT claims
+ return Jwts.builder().setSubject(username).claim("userId", userId) // Add userId as a claim
+ .setIssuedAt(now).setExpiration(expiryDate).signWith(getSigningKey(), SignatureAlgorithm.HS256)
+ .compact();
+ }
+
+ // Validate and parse JWT Token
+ public Claims validateToken(String token) {
+ try {
+ return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
+ } catch (Exception e) {
+ return null; // Handle token parsing/validation errors
+ }
+ }
+
+ public String extractUsername(String token) {
+ return extractClaim(token, Claims::getSubject);
+ }
+
+ public T extractClaim(String token, Function claimsResolver) {
+ final Claims claims = extractAllClaims(token);
+ return claimsResolver.apply(claims);
+ }
+
+ private Claims extractAllClaims(String token) {
+ return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
+ }
+}