Could someone help me understand the issue? Everything works fine on the backend. The problem lies specifically on the frontend. The user registers on the page at http://localhost:8080/host_page, and the data is handled by the RegisterController. If registration is successful, the user is redirected to the page http://localhost:8080/personal_office. The issue is with managing the JWT token on the frontend. When I turn off security checks, all pages in the browser open. What and where should I add to make the frontend retrieve the JWT token from the backend, store it in the browser's local storage, and prevent the user from receiving a 403 error?This is my first experience in passing the JWT token from the backend to the frontend. I couldn't find suitable articles online about my situation. Here is my controller.
@RestController @RequiredArgsConstructor @Slf4j @RequestMapping("/register") public class RegisterController { private final UserService userService; private final DatabaseUserDetailsService databaseUserDetailsService; private final JWTService jwtService; private final PaymentController paymentController; private final SubscriptionRepository subscriptionRepository; @PostMapping public ResponseEntity<?> registerUser(@RequestBody UserRegistrationDTO request) { try { if (userService.isPhoneNumberRegistered(request.getPhoneNumber())) { log.error("User with phone number {} already exists", request.getPhoneNumber()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("User with phone number " + request.getPhoneNumber() +" already exists"); } if (userService.isEmailRegistered(request.getEmail())) { log.error("User with email {} already exists", request.getEmail()); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("User with email " + request.getEmail() +" already exists"); } BigDecimal bonusPrice = subscriptionRepository.findBySubscriptionName("REGISTRATION").getSubscriptionPrice(); TransactionDTO transactionDTO = TransactionDTO.builder() .outputCardNumber(request.getUserBankCard().getCardNumber()) .sum(bonusPrice) .cardExpirationDate(request.getUserBankCard().getCardExpirationDate()) .cvv(request.getUserBankCard().getCvv()).build(); ResponseEntity<String> paymentResponse = paymentController.payment(transactionDTO); if (paymentResponse.getStatusCode().is2xxSuccessful()) { userService.registerUser(request); UserDetails userDetails = databaseUserDetailsService.loadUserByUsername(String.valueOf(request.getPhoneNumber())); String jwtToken = jwtService.generateJwtToken(userDetails); log.info("User with phone number {} registered successfully ", request.getPhoneNumber()); log.info("Generated JWT token: {}", jwtToken); return ResponseEntity.ok(new RedirectResponseDTO("/personal_office", jwtToken)); } else if (paymentResponse.getStatusCode() == HttpStatus.BAD_REQUEST) { String errorMessage = paymentResponse.getBody(); log.warn("Payment failed: {}", errorMessage); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorMessage); } else { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Payment failed"); } } catch (IllegalArgumentException e) { log.warn(e.getMessage()); return ResponseEntity.badRequest().body(e.getMessage()); } catch (Exception e) { log.error("An error occurred while updating subscription", e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An unexpected error occurred"); } } }my WebSecurityConfig
@Configuration @RequiredArgsConstructor @EnableWebSecurity public class WebSecurityConfig { private final JWTTokenConfig jwtTokenConfig; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf().disable() .cors().disable() .authorizeRequests(authorize -> authorize .antMatchers("/host_page", "/register", "/login" ).permitAll() .antMatchers("/swagger-ui/**", "/swagger-resources/*", "/v3/api-docs/**", "/swagger-ui.html").permitAll() .antMatchers("/personal_office/**").authenticated() .antMatchers(HttpMethod.GET, "/main").permitAll() .antMatchers("/free_subscription").hasAnyRole("FREE", "OPTIMAL", "MAXIMUM", "ADMIN") .antMatchers("/optimal_subscription").hasAnyRole("MAXIMUM", "OPTIMAL", "ADMIN") .antMatchers("/maximum_subscription").hasAnyRole("MAXIMUM", "ADMIN") .antMatchers("/admin_office/**").hasRole("ADMIN") .anyRequest().authenticated() ) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore((Filter) jwtTokenConfig, UsernamePasswordAuthenticationFilter.class); return http.build(); } }and my HTML files
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Host Page</title><style> body { font-family: Arial, sans-serif; } .welcome { text-align: center; } .form-container { display: flex; justify-content: space-around; align-items: stretch; } form { width: 45%; border: 1px solid #ccc; padding: 20px; border-radius: 4px; display: flex; flex-direction: column; } h2 { text-align: center; } label { display: block; margin-bottom: 5px; text-align: center; } input[type="text"], input[type="password"] { width: 100%; padding: 10px; margin-bottom: 15px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px; } input[type="submit"] { width: 100%; padding: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; } input[type="submit"]:hover { background-color: #45a049; } .error { color: red; font-size: 14px; text-align: center; } .form-group { margin-bottom: 15px; text-align: center; } .form-group label { display: block; } .form-group input[type="text"] { width: 100%; padding: 10px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px; margin-bottom: 5px; } .form-group .half-width { width: calc(50% - 5px); display: inline-block; vertical-align: top; } .form-group .half-width label { display: block; } .form-group .half-width input[type="text"] { width: calc(100% - 10px); margin-bottom: 0; }</style><script> function submitRegistrationForm(event) { event.preventDefault(); var phoneNumber = document.getElementById('regPhoneNumber').value; var email = document.getElementById('regEmail').value; var bankCardNumber = document.getElementById('regBankCardNumber').value; var cardExpirationDate = document.getElementById('cardExpirationDate').value; var cvv = document.getElementById('cvv').value; var password = document.getElementById('regPassword').value; var userData = { phoneNumber: phoneNumber, email: email, userBankCard: { cardNumber: bankCardNumber, cardExpirationDate: cardExpirationDate, cvv: cvv }, password: password }; fetch('http://localhost:8080/register', { method: 'POST', headers: {'Content-Type': 'application/json;charset=UTF-8' }, body: JSON.stringify(userData) }) .then(response => { if (response.ok) { return response.json(); } else { return response.text().then(text => { throw new Error(text) }); } }) .then(data => { localStorage.setItem('jwtToken', data.jwtToken); window.location.href = 'http://localhost:8080/personal_office'; }) .catch(error => { console.error('Error:', error); }); }</script></head><body><h1 class="welcome">Welcome to Host Page</h1><div class="form-container"><form id="registrationForm" onsubmit="submitRegistrationForm(event)" method="post"><h2>Registration Form</h2><div class="form-group"><label for="regPhoneNumber">Phone Number:</label><input type="text" id="regPhoneNumber" name="phoneNumber" required></div><div class="form-group"><label for="regEmail">Email:</label><input type="text" id="regEmail" name="email" required></div><div class="form-group"><label for="regBankCardNumber">Bank Card Number:</label><input type="text" id="regBankCardNumber" name="bankCardNumber" required></div><div class="form-group"><div class="half-width"><label for="cardExpirationDate">Card Expiration Date:</label><input type="text" id="cardExpirationDate" name="cardExpirationDate" required></div><div class="half-width"><label for="cvv">CVV:</label><input type="text" id="cvv" name="cvv" required></div></div><div class="form-group"><label for="regPassword">Password:</label><input type="password" id="regPassword" name="password" required></div><div class="error" id="registrationErrorMessages" style="display: none;"></div><input type="submit" value="Register"></form><form id="loginForm" onsubmit="submitLoginForm(event)" method="post"><h2>Login Form</h2><div class="form-group"><label for="loginPhoneNumber">Phone Number:</label><input type="text" id="loginPhoneNumber" name="phoneNumber" required></div><div class="form-group"><label for="loginPassword">Password:</label><input type="password" id="loginPassword" name="password" required></div><div class="error" id="loginErrorMessages" style="display: none;"></div><input type="submit" value="Login"></form></div></body></html><!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>User Dashboard</title><style> body { font-family: Arial, sans-serif; margin: 0; padding: 0; } header { background-color: #333; color: #fff; padding: 10px; text-align: center; } nav { background-color: #f4f4f4; padding: 10px; text-align: center; } nav a { text-decoration: none; color: #333; padding: 10px; margin: 0 5px; } section { padding: 20px; }</style></head><body><header><h1>Welcome to User Dashboard</h1></header><nav><a href="/user/personal_data">Personal Data</a><a href="/user/my_subscriptions">My Subscriptions</a><a href="/user/all_subscriptions">All Subscriptions</a></nav><section><div th:text="${content}"></div></section><script> const urlParams = new URLSearchParams(window.location.search); const jwtToken = urlParams.get('jwtToken'); if (jwtToken) { localStorage.setItem('jwtToken', jwtToken); } else { window.location.href = "/host_page"; }</script></body></html>Where are the errors? What needs to be done? Maybe someone will provide a link to the necessary article, or maybe someone will write the correct script and indicate where to put it.