<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anbumani</title>
    <description>The latest articles on DEV Community by Anbumani (@amailath).</description>
    <link>https://dev.to/amailath</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1245595%2Fa5bd1fa7-a13b-4b8d-98c3-215b5a8e33bf.jpg</url>
      <title>DEV Community: Anbumani</title>
      <link>https://dev.to/amailath</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amailath"/>
    <language>en</language>
    <item>
      <title>Secure Your Spring Boot and Angular Application with JWT Authentication: A Comprehensive Guide</title>
      <dc:creator>Anbumani</dc:creator>
      <pubDate>Mon, 08 Jan 2024 03:04:20 +0000</pubDate>
      <link>https://dev.to/amailath/secure-your-spring-boot-and-angular-application-with-jwt-authentication-a-comprehensive-guide-3o64</link>
      <guid>https://dev.to/amailath/secure-your-spring-boot-and-angular-application-with-jwt-authentication-a-comprehensive-guide-3o64</guid>
      <description>&lt;p&gt;In the world of web development, security is a critical aspect that cannot be overlooked. This blog post will guide you through the process of securing your Spring Boot backend and Angular frontend using JSON Web Tokens (JWT) for authentication. We'll cover the generation and validation of JWT on the server side, as well as implement the necessary features on the Angular side to handle authentication, error interception, and token storage.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/V9SXJQmlOvM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding JWT and Its Significance
&lt;/h2&gt;

&lt;p&gt;JSON Web Tokens (JWT) have emerged as a key element in securing modern web applications, offering a compact and efficient way to transmit information between parties. Below is a brief overview of JWT and its pivotal role in contemporary web development:&lt;/p&gt;

&lt;h3&gt;
  
  
  What is JWT?
&lt;/h3&gt;

&lt;p&gt;JWT is an open standard that defines a self-contained method for securely transmitting information as a JSON object. JWTs are commonly used for authentication, authorization, and secure communication by comprising a header, payload, and signature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Components of a JWT:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Header:&lt;/strong&gt; Specifies the token type and signing algorithm.&lt;br&gt;
&lt;strong&gt;Payload:&lt;/strong&gt; Contains claims and additional data.&lt;br&gt;
&lt;strong&gt;Signature:&lt;/strong&gt; Ensures the token's integrity and is created by combining the encoded header, payload, and a secret key.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3i8se82532j9l3ye1ckz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3i8se82532j9l3ye1ckz.jpg" alt="Components of a JWT" width="800" height="83"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Role of JWT in Modern Web Applications:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Stateless Authentication:&lt;/strong&gt; JWTs eliminate the need for server-side session storage, allowing stateless authentication in scalable systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization:&lt;/strong&gt; JWTs carry user claims, aiding servers in making access control decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inter-Service Communication:&lt;/strong&gt; JWTs facilitate secure communication between microservices, ensuring authenticity and authorization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compact and Efficient:&lt;/strong&gt; The concise format of JWTs makes them ideal for transmitting information efficiently.&lt;/p&gt;
&lt;h3&gt;
  
  
  Advantages of JWT:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Security:&lt;/strong&gt; JWTs can be signed and encrypted for integrity and confidentiality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decentralized:&lt;/strong&gt; JWTs are self-contained, reducing the need for constant communication with a central authority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-Domain Compatibility:&lt;/strong&gt; JWTs can be easily transmitted across different domains and are widely supported.&lt;/p&gt;
&lt;h3&gt;
  
  
  Considerations:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Token Expiry:&lt;/strong&gt; JWTs can have an expiration time for enhanced security.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sensitive Information:&lt;/strong&gt; Avoid including highly sensitive information in the payload to minimize security risks.&lt;/p&gt;

&lt;p&gt;thus, JWTs serve as a versatile and secure solution for authentication, authorization, and information exchange in modern web applications, contributing to the evolving landscape of web development.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting Up Spring Boot for JWT Authentication
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Create an application setup with spring security. You can refer to my previous post to set up one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Implementing JWT Service.
&lt;/h3&gt;

&lt;p&gt;After successful authentication, the application will generate and sign the JWT with claims, expiration, and other parameters. Below is the flow that explains the JWT token generation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2zcmxfbj67a8x8zaag8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2zcmxfbj67a8x8zaag8.jpg" alt="JWT Token Generation" width="800" height="1184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's configure the dependencies below for JWT support. This will help us in JWT generation and validation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.jsonwebtoken&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;jjwt-api&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;0.11.5&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.jsonwebtoken&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;jjwt-impl&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;0.11.5&amp;lt;/version&amp;gt;
            &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.jsonwebtoken&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;jjwt-jackson&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;0.11.5&amp;lt;/version&amp;gt;
            &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As a next step, we will create a service that will generate and validate JWT.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;io.jsonwebtoken.Jwts&lt;/em&gt; provides a handy builder method to build the JWT.&lt;/p&gt;

&lt;p&gt;Let's create a secret key using the HMACSHA256 algorithm. This key will be used to ensure the integrity of JWT.&lt;/p&gt;
&lt;h3&gt;
  
  
  JWT Generate method
&lt;/h3&gt;

&lt;p&gt;With the builder method let's set the issuer of JWT, Subject, Custom claim &lt;em&gt;"username"&lt;/em&gt;, and the expiration. Finally, sign the JWT with the secret key.&lt;/p&gt;
&lt;h3&gt;
  
  
  JWT Validate Method
&lt;/h3&gt;

&lt;p&gt;We will use the JWT parser using the secret key to parse the claims from the JWT.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code below shows the complete JWT service implementation&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class JWTServiceImpl implements JWTService {

    private final String key = "jxgEQeXHuPq8VdbyYFNkANdudQ53YUn4";
    private final SecretKey secretKey = Keys.hmacShaKeyFor(key.getBytes(StandardCharsets.UTF_8));

    @Override
    public String generateJwt(String username) throws ParseException {
        Date date= new Date();
        return  Jwts.builder()
                .setIssuer("MFA Server")
                .setSubject("JWT Auth Token")
                .claim("username", username)
                .setIssuedAt(date)
                .setExpiration(new Date(date.getTime() + 60000))
                .signWith(secretKey)
                .compact();
    }

    @Override
    public Authentication validateJwt(String jwt) {
        JwtParser jwtParser = Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build();
        Claims claims = jwtParser.parseClaimsJws(jwt).getBody();
        String username = (String)claims.getOrDefault("username",null);
        if(Objects.nonNull(username)){
            return new UsernamePasswordAuthenticationToken(username, null, new ArrayList&amp;lt;&amp;gt;());
        }
        return null;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Configuring Spring Security for JWT validation.
&lt;/h3&gt;

&lt;p&gt;To validate JWT we will create a custom filter that retrieves the token from incoming requests and sets the authorization token to the security context. Also, We will create an Exception handler that responds with 401 went the user is not authenticated.&lt;/p&gt;
&lt;h3&gt;
  
  
  JWT Validation Filter
&lt;/h3&gt;

&lt;p&gt;This filter will be configured to execute before the &lt;em&gt;"UsernameAndPasswordAuthenticvationFilter"&lt;/em&gt;. This filter extends the OncePerRequestFiolter and provides the implantation to doFilter.&lt;/p&gt;

&lt;p&gt;We will validate the JWt from the request by extracting the authorization header and using our JWT service to validate and set the authentication token to the security context. Please see the implementation below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public JwtValidationFilter(JWTService jwtService) {
        this.jwtService = jwtService;
    }


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            //retrieve token
            String jwt = getJWT(request);
            if (Objects.nonNull(jwt)) {
                // Validate the JWT from the Request
                UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) jwtService.validateJwt(jwt);
                auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(auth);
            }
        }catch (Exception e){
            log.error("Exception while processing the JWT"+e.getMessage());
        }
        filterChain.doFilter(request, response);
    }

    private String getJWT(HttpServletRequest request){
        String jwt = request.getHeader("authorization");
        if(Objects.nonNull(jwt) &amp;amp;&amp;amp; jwt.startsWith("Bearer") &amp;amp;&amp;amp;
        jwt.length()&amp;gt;7){
            return jwt.substring(7);
        }
        return null;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Exception Handler
&lt;/h2&gt;

&lt;p&gt;When there is any exception in the process of authentication we will respond with 401 - Unauthorized error. This is achieved using the Authentication Entry point. Where we will configure the exception handler. Look at the simple implementation below.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component
@Slf4j
public class AuthExceptionHandler implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        log.error("Unauthorized {}", authException.getMessage());
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "User is not Authenticated");
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Managing Cross-Origin Resource Sharing (CORS) to ensure secure communication.
&lt;/h3&gt;

&lt;p&gt;Our angular application is running on a different port than the back end. it is considered a different domain. So we need to advise Spring Security to share data to the Cross Origins.&lt;/p&gt;

&lt;p&gt;Let's use the CORS configuration to set allowed Origins, Methods, and headers. As we are expecting authorization and content-type header let's add them. For any URL in the application add this configuration using &lt;em&gt;UrlBasedCorsConfigurationSource&lt;/em&gt; object.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @Bean
    CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowedHeaders(Arrays.asList("authorization","content-type"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",configuration);
        return source;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, we add this to the security configuration.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Bean
    public SecurityFilterChain defaultFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .cors(cors-&amp;gt; cors.configurationSource(corsConfigurationSource()))
                .csrf(csrf-&amp;gt; csrf.disable())
                .exceptionHandling(handle -&amp;gt; handle.authenticationEntryPoint(authExceptionHandler))
                .addFilterBefore(jwtValidationFilter, UsernamePasswordAuthenticationFilter.class)
                .sessionManagement(session-&amp;gt; session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth-&amp;gt; auth
                        .requestMatchers("/error**","confirm-email","/register**","/login**","/verifyTotp**").permitAll()
                        .anyRequest().authenticated()
                )
               .build();
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Angular Setup for JWT Authentication
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Storing JWT in Local Storage
&lt;/h3&gt;

&lt;p&gt;On successful authentication, we will add the JWT to local storage and further, it will be used by the application for backend API calls.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ucl4y34q01y94tjcrql.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ucl4y34q01y94tjcrql.jpg" alt="Store JWT" width="800" height="660"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public login(payload: MfaVerificationResponse): void {
    if(payload.tokenValid &amp;amp;&amp;amp; !payload.mfaRequired){
      localStorage.clear();
      localStorage.setItem(this.tokenKey, payload.jwt);
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Adding JWT to outgoing requests for secure communication with the backend.
&lt;/h3&gt;

&lt;p&gt;HTTP Interceptors from angular allow us to intercept all the requests and responses. We will create two interceptors one to add the authorization token to the request header and another to redirect user to login page if the user is unauthorized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8hjztmcgt63vvnkle4t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh8hjztmcgt63vvnkle4t.jpg" alt="Interceptor Workflow" width="800" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jwt Token Interceptor Implementation&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Injectable({
  providedIn: 'root'
})
export class TokenInterceptor implements HttpInterceptor {

  constructor(private authenticationService: AuthService) { }


  intercept(
    request: HttpRequest&amp;lt;any&amp;gt;,
    next: HttpHandler
  ): Observable&amp;lt;HttpEvent&amp;lt;any&amp;gt;&amp;gt; {
    if (this.authenticationService.isLoggedIn()) {
      let newRequest = request.clone({
        setHeaders: {
          Authorization: `Bearer ${this.authenticationService.getToken()}`,
        },
      });
      return next.handle(newRequest);
    }
    return next.handle(request);
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Setting up an error interceptor for better error handling.
&lt;/h3&gt;

&lt;p&gt;Error handler will skip the login page from 401 validation. If the backend responds with 401 for any API call then it is assumed the user should log in again to get access. We can customize this when we have role-level access.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Injectable({
  providedIn: 'root'
})
export class ErrorInterceptor implements HttpInterceptor {

  constructor(private authenticationService: AuthService) { }


  intercept(
    request: HttpRequest&amp;lt;any&amp;gt;,
    next: HttpHandler
  ): Observable&amp;lt;HttpEvent&amp;lt;any&amp;gt;&amp;gt; {

    return next.handle(request).pipe(catchError(error=&amp;gt;{
      if(error.status == 401 &amp;amp;&amp;amp; !this.isLoginPage(request)){
        this.authenticationService.logout();
      }
      const errMsg = error.error.message || error.statusText;
      return throwError(()=&amp;gt; errMsg);
    }));
  }

  private isLoginPage(request: HttpRequest&amp;lt;any&amp;gt;){
    return request.url.includes("/login") || request.url.includes("/verifyTotp");
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Along the logout, we will clear the token from local storage and navigate the user to login page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  public logout() {
    localStorage.removeItem(this.tokenKey);
    this.router.navigate(['/login']);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now let's call a protected URL on the Home page load.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class HomeComponent implements OnInit {
  message: string="";
  constructor(private homeService: HomeService) { }

  ngOnInit(): void {
    this.homeService.getProtectedString().subscribe(s=&amp;gt; this.message =s);
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Home HTML&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="container-fluid"&amp;gt;
&amp;lt;div class="card"&amp;gt;
    &amp;lt;div class="card-header"&amp;gt;
        &amp;lt;h1&amp;gt;Welcome!!&amp;lt;/h1&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class="card-body"&amp;gt;
        &amp;lt;h2&amp;gt;{{message}}&amp;lt;/h2&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Let's execute the code and check it out.
&lt;/h2&gt;

&lt;p&gt;After successful login, you can see the bearer token is added to the header and we have received the response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnoolbz198cbnmviybajh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnoolbz198cbnmviybajh.png" alt="UI Home Page" width="800" height="414"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F876iugt53lf4rsshmcza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F876iugt53lf4rsshmcza.png" alt="200 OK from backend" width="678" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have successfully secured the Spring boot and Angular application using JWT. Great for reading till the end. Check out the GitHub repository &amp;amp; do comment if have any questions, I am happy to answer all.&lt;/p&gt;

&lt;p&gt;Backend code&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/mfaserver" rel="noopener noreferrer"&gt;
        mfaserver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Spring boot backend for MFA
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;MFA Server&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Application for 2FA demo.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;APIs Involved&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;login&lt;/li&gt;
&lt;li&gt;register&lt;/li&gt;
&lt;li&gt;verifyTotp&lt;/li&gt;
&lt;li&gt;confrim-email&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Dependencies&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;dev.samstevens.totp&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/mfaserver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Angular UI&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;
        MFAApplication
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Mfaapplication&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Application developed using Angular 14 and Bootstrap.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Components involved.&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Register&lt;/li&gt;
&lt;li&gt;TOTP&lt;/li&gt;
&lt;li&gt;Home Module&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>angular</category>
      <category>springboot</category>
      <category>security</category>
      <category>jwt</category>
    </item>
    <item>
      <title>Connecting Kafka to Spring Boot: A Step-by-Step Guide Using KafkaTemplate</title>
      <dc:creator>Anbumani</dc:creator>
      <pubDate>Thu, 04 Jan 2024 02:54:41 +0000</pubDate>
      <link>https://dev.to/amailath/connecting-kafka-to-spring-boot-a-step-by-step-guide-using-kafkatemplate-18pc</link>
      <guid>https://dev.to/amailath/connecting-kafka-to-spring-boot-a-step-by-step-guide-using-kafkatemplate-18pc</guid>
      <description>&lt;p&gt;Hello, Tech enthusiasts! Today, we're going to learn how to connect to one of the most widely used distributed streaming platforms, Kafka, from Spring Boot. This will be a brief write-up as we'll be utilizing KafkaTemplate, which makes our lives easier. Let's dive in.&lt;/p&gt;

&lt;p&gt;If you like to learn in action, below is the video version that goes over the implementation.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/IkvHF5Txgs4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;We will create a Rest endpoint that will be responsible for posting the message into the Kafka topic and the consumer who is also part of the same project listening to the topic will print the received message on the console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Set-up
&lt;/h2&gt;

&lt;p&gt;Let's create a spring boot application with the following dependencies.&lt;br&gt;
Add "spring-boot-starter-web" for the rest endpoint creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;             
      &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here comes the Kafka dependency will do the magic of producing &amp;amp; consuming from Kafka via KafkaTemplate.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.springframework.kafka&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-kafka&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As the next step will add below configuration to establish the connection with Kafka broker. Spring boot will auto-configure the KafkaTemplate with these properties.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to update the server and group-id below.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  kafka:
    consumer:
      bootstrap-servers:
        - localhost:9092
      group-id: ytube-group
#      auto-offset-reset: earliest
#      key-deserializer:
#      value-deserializer:
    producer:
      bootstrap-servers:
        - localhost:9092
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Consumer Configuration:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;bootstrap-servers: Specifies the Kafka server(s) that the consumer will connect to. In this case, it's set to a single server at localhost:9092.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;group-id: Identifies the consumer group to which this consumer belongs. It helps Kafka keep track of the progress of different consumer groups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;auto-offset-reset: (Commented out) This property determines what happens when there is no initial offset or the current offset does not exist. The earliest option means it will start reading from the beginning of the topic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;key-deserializer and value-deserializer: (Commented out) These properties define the deserializer classes for the key and value of the messages. Depending on your use case, you might need to specify appropriate deserializer classes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Producer Configuration:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;bootstrap-servers: Similar to the consumer, this property specifies the Kafka server(s) that the producer will connect to. In this case, it's also set to a single server at localhost:9092.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  KafkaMessageProducer
&lt;/h2&gt;

&lt;p&gt;With KafkaTemplate, it's as simple as writing a letter. Create a KafkaProducer service, autowire KafkaTemplate, and start sending messages.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component
public class KafkaMessageProducer {

    @Autowired
    KafkaTemplate&amp;lt;String, String&amp;gt; kafkaTemplate;

    public void sendMessage(String topic, String message){
        kafkaTemplate.send(topic, message);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  KafkaMessageConsumer
&lt;/h2&gt;

&lt;p&gt;Of course, every good story has two sides. Create a KafkaConsumer service to catch the messages on the other end. KafkaTemplate sends, and KafkaConsumer receives – it's the yin and yang of our messaging world. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We configure the consumer with the help of KafkaListener.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component
public class MessageConsumer {

    @KafkaListener(topics = "ytube-topic1", groupId = "ytube-group")
    public void consumerMessage(String message){
        System.out.println("Received Message "+ message);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's make the rest endpoint to post the message into the Kafka topic. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We have autowired the kafka message producer and passed the topic name and message.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @Autowired
    KafkaMessageProducer messageProducer;

    @PostMapping("/sendMessage")
    public String sendMessage(@RequestParam("message") String message){
        messageProducer.sendMessage("ytube-topic1", message);
        return "Message has been sent successfully "+message;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's execute the application and see the message posted to Kafka topic and received by the consumer. In real world, the consumer can be another microservice that consumes the message to process it further. &lt;/p&gt;

&lt;p&gt;Kudos, you made it to the end! Thanks for hanging out with us. If you have more questions or just enjoyed the ride, come back soon. Happy exploring!&lt;/p&gt;

&lt;p&gt;Checkout the completed code here &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/kafkademo" rel="noopener noreferrer"&gt;
        kafkademo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Demo/Starter project to connect Spring boot with Kafka
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Simple Kafka Demo&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;The application demonstrates the use of KafkaTemplate. We will use Kafka template to produce and consume the message.&lt;/p&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/kafkademo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>springboot</category>
      <category>kafka</category>
      <category>java</category>
      <category>stream</category>
    </item>
    <item>
      <title>Streamlining Email Verification: A Step-by-Step Guide with Spring Boot and Angular</title>
      <dc:creator>Anbumani</dc:creator>
      <pubDate>Tue, 02 Jan 2024 00:13:26 +0000</pubDate>
      <link>https://dev.to/amailath/streamlining-email-verification-a-step-by-step-guide-with-spring-boot-and-angular-eff</link>
      <guid>https://dev.to/amailath/streamlining-email-verification-a-step-by-step-guide-with-spring-boot-and-angular-eff</guid>
      <description>&lt;p&gt;Hello readers, In this article you will learn a complete email verification process. We will implement this using Java, Spring Boot, and Mongo DB. You find the completed code at the end. Also, the video version is below.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/qdZTwMVFvP0"&gt;
&lt;/iframe&gt;
  &lt;/p&gt;

&lt;p&gt;Let us split this process into two parts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generating email verification link with the token.&lt;/li&gt;
&lt;li&gt;Rest endpoint to verify the token from the link.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Workflow
&lt;/h2&gt;

&lt;p&gt;As the first process, we will generate the token, Store it in DB, and send an email with the confirmation link. This will be included after we persist the user details in the registration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Additionally you can also create an endpoint that can be utilized when there is an email update.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbj3ggc2l5xzz5zebt5p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgbj3ggc2l5xzz5zebt5p.jpg" alt="Generate Token &amp;amp; Send email Workflow" width="800" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An endpoint that verifies the token by querying the DB and updating the user record that the email has been verified.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpprh5qq4a1ma4j63t54k.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpprh5qq4a1ma4j63t54k.jpg" alt="Confirm-email endpoint workflow" width="800" height="778"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Code Implementation
&lt;/h2&gt;

&lt;p&gt;Let's create an entity that stores the token. This can be leveraged for future use when there is a business requirement for token expiration and many more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
@Document
public class EmailConfirmationToken {
    @Id
    private String id;
    @Indexed
    private String token;
    @CreatedDate
    @ReadOnlyProperty
    private LocalDateTime timeStamp;
    @DBRef
    private User user;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Below is the repository that will interact with DB.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Repository
public interface EmailConfirmationTokenRepository extends MongoRepository&amp;lt;EmailConfirmationToken, String&amp;gt; {
    EmailConfirmationToken findByToken(String token);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now repository is ready, Let's create a service that generates the token,&lt;/p&gt;

&lt;p&gt;We will make use of "KeyGenerators" from spring security to generate a random 15-byte token.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private static final BytesKeyGenerator DEFAULT_TOKEN_GENERATOR = KeyGenerators.secureRandom(15);
    private static final Charset US_ASCII = Charset.forName("US-ASCII");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now use the DEFAULT_TOKEN_GENERATOR to generate the token and add it to the entity to store it using the repository we created above.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String tokenValue = new String(Base64.encodeBase64URLSafe(DEFAULT_TOKEN_GENERATOR.generateKey()), US_ASCII);
        EmailConfirmationToken emailConfirmationToken = new EmailConfirmationToken();
        emailConfirmationToken.setToken(tokenValue);
        emailConfirmationToken.setTimeStamp(LocalDateTime.now());
        emailConfirmationToken.setUser(user);
        emailConfirmationTokenRepository.save(emailConfirmationToken);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;At this point, the token has been generated and stored in DB. Now let's send out a registration email.&lt;/p&gt;

&lt;p&gt;To Configure the email server we are going to use Gmail. Let's move to &lt;strong&gt;Gmail-&amp;gt; Manage Accounts -&amp;gt; Security -&amp;gt; click on 2 Step Verification -&amp;gt; Scroll to the end and click on App Passwords -&amp;gt; Enter the application name and get the password&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After you get the password add it to the configuration below,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: YOUR_EMAIL
    password: "YOUR APPPLICATION PASSWORD"
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            required: true
            enable: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now the email server configuration is ready let's implement the email service as below,&lt;/p&gt;

&lt;p&gt;Email service makes use of JavaMailSender API. As we are planning to use HTML messages, I am using the MIME message type and its helper to set the email properties.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can also isolate the HTML message to a separate file and include it as a stream instead of an inline string.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class EmailServiceImpl implements EmailService {

    private final JavaMailSender sender;

    public EmailServiceImpl(JavaMailSender sender) {
        this.sender = sender;
    }

    @Override
    public void sendConfirmationEmail(EmailConfirmationToken emailConfirmationToken) throws MessagingException {
        //MIME - HTML message
        MimeMessage message = sender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setTo(emailConfirmationToken.getUser().getUsername());
        helper.setSubject("Confirm you E-Mail - MFA Application Registration");
        helper.setText("&amp;lt;html&amp;gt;" +
                        "&amp;lt;body&amp;gt;" +
                        "&amp;lt;h2&amp;gt;Dear "+ emailConfirmationToken.getUser().getFirstName() + ",&amp;lt;/h2&amp;gt;"
                        + "&amp;lt;br/&amp;gt; We're excited to have you get started. " +
                        "Please click on below link to confirm your account."
                        + "&amp;lt;br/&amp;gt; "  + generateConfirmationLink(emailConfirmationToken.getToken())+"" +
                        "&amp;lt;br/&amp;gt; Regards,&amp;lt;br/&amp;gt;" +
                        "MFA Registration team" +
                        "&amp;lt;/body&amp;gt;" +
                        "&amp;lt;/html&amp;gt;"
                , true);

        sender.send(message);
    }

    private String generateConfirmationLink(String token){
        return "&amp;lt;a href=http://localhost:8080/confirm-email?token="+token+"&amp;gt;Confirm Email&amp;lt;/a&amp;gt;";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's add the token generation and send an email after saving user details in your application.&lt;/p&gt;

&lt;p&gt;Let's see how it works in action.&lt;/p&gt;

&lt;p&gt;Open the UI and register a User with a valid email address,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlogzekc98vd5xryv7ao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlogzekc98vd5xryv7ao.png" alt="Registration" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon registration, let's look at the DB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yeyse7c22c3c4grci23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5yeyse7c22c3c4grci23.png" alt="User Document" width="800" height="302"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqq8tr5avfx5g7ny7ar7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqq8tr5avfx5g7ny7ar7.png" alt="Email Confirmation Document" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the email we received.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1srkcyvwdew385k9wp8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz1srkcyvwdew385k9wp8.png" alt="Inbox Received confirmation email" width="800" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzli6rgtollxzyc4gd6hl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzli6rgtollxzyc4gd6hl.png" alt="Received email body" width="686" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first part is completed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let's implement the rest endpoint that validates the token,&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;If there is a security config that limits the authenticated endpoints then add this endpoint to whitelists.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@GetMapping("/confirm-email")
    public ResponseEntity&amp;lt;?&amp;gt; confirmEmail(@RequestParam("token") String token) throws InvalidTokenException {
        try{
            if(userService.verifyUser(token)){
                return ResponseEntity.ok("Your email has been successfully verified.");
            } else {
                return ResponseEntity.ok("User details not found. Please login and regenerate the confirmation link.");
            }
        } catch (InvalidTokenException e){
            return ResponseEntity.ok("Link expired or token already verified.");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Below is the service implementation that will validate the token and update the user record.&lt;/p&gt;

&lt;p&gt;Code retries the token from DB with the token received from the endpoint. if there is a token then validate update the user record and delete the token from DB.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
    public boolean verifyUser(String token) throws InvalidTokenException {
        EmailConfirmationToken emailConfirmationToken = emailConfirmationTokenRepository.findByToken(token);
        if(Objects.isNull(emailConfirmationToken) || !token.equals(emailConfirmationToken.getToken())){
            throw new InvalidTokenException("Token is not valid");
        }
        User user = emailConfirmationToken.getUser();
        if (Objects.isNull(user)){
            return false;
        }
        user.setAccountVerified(true);
        userRepository.save(user);
        emailConfirmationTokenRepository.delete(emailConfirmationToken);
        return true;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let's check the endpoint by clicking on the email link.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz1a69hv1iq9ira3bknv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz1a69hv1iq9ira3bknv.png" alt="Email with confirmation link" width="686" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61ewhhaqcz6d4ndodiyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61ewhhaqcz6d4ndodiyb.png" alt="Response from server" width="586" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This endpoint also updated the record and deleted the token,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkanr32e13tcio08rnezt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkanr32e13tcio08rnezt.png" alt="Updated account verified" width="800" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffv17xc1vvz8xw6yyd6aq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffv17xc1vvz8xw6yyd6aq.png" alt="Removed the token from DB" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have successfully implemented the registration workflow. Great for reading till the end. Check out the GitHub repository &amp;amp; do comment if have any questions, I am happy to answer all.&lt;/p&gt;

&lt;p&gt;Backend code&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/mfaserver" rel="noopener noreferrer"&gt;
        mfaserver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Spring boot backend for MFA
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;MFA Server&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Application for 2FA demo.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;APIs Involved&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;login&lt;/li&gt;
&lt;li&gt;register&lt;/li&gt;
&lt;li&gt;verifyTotp&lt;/li&gt;
&lt;li&gt;confrim-email&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Dependencies&lt;/h3&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;dev.samstevens.totp&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/mfaserver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Angular UI&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;
        MFAApplication
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Mfaapplication&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Application developed using Angular 14 and Bootstrap.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Components involved.&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Register&lt;/li&gt;
&lt;li&gt;TOTP&lt;/li&gt;
&lt;li&gt;Home Module&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>email</category>
      <category>springboot</category>
      <category>mongodb</category>
      <category>restapi</category>
    </item>
    <item>
      <title>Securing Your App: TOTP Authentication with Spring Boot and Angular — Part Two— Implementation &amp; Demo</title>
      <dc:creator>Anbumani</dc:creator>
      <pubDate>Sun, 31 Dec 2023 23:14:00 +0000</pubDate>
      <link>https://dev.to/amailath/securing-your-app-totp-authentication-with-spring-boot-and-angular-part-two-implementation-demo-594o</link>
      <guid>https://dev.to/amailath/securing-your-app-totp-authentication-with-spring-boot-and-angular-part-two-implementation-demo-594o</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a continuation of Part 1 — Overview and Project Setup. Please go through it if you have not.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/5Uk4i2iDVPY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Register Endpoint Implementation
&lt;/h2&gt;

&lt;p&gt;As the first step let’s implement the register endpoint. Below operations involved in this process,&lt;br&gt;
The controller delegates the service request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping("/register")
    public ResponseEntity&amp;lt;?&amp;gt; register(@Validated @RequestBody User user) {
        // Register User // Generate QR code using the Secret KEY
        try {
            return ResponseEntity.ok(userService.registerUser(user));
        } catch (QrGenerationException e) {
            return ResponseEntity.internalServerError().body("Something went wrong. Try again.");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Service layer for Registration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the user already exists in DB with the same username.&lt;/li&gt;
&lt;li&gt;Hash the password&lt;/li&gt;
&lt;li&gt;Create a Secret key that is used for TOTP generation&lt;/li&gt;
&lt;li&gt;Save these data into DB&lt;/li&gt;
&lt;li&gt;Generate QR code and respond.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
    public MfaTokenData registerUser(User user) throws UserAlreadyExistException, QrGenerationException {
        try{
            if (userRepository.findByUsername(user.getUsername()).isPresent()) {
                throw new UserAlreadyExistException("Username already exists");
            }
            user.setPassword(passwordEncoder.encode(user.getPassword()));
            //some additional work
            user.setSecretKey(totpManager.generateSecretKey()); //generating the secret and store with profile
            User savedUser = userRepository.save(user);

            //Generate the QR Code
            String qrCode = totpManager.getQRCode(savedUser.getSecretKey());
            return MfaTokenData.builder()
                    .mfaCode(savedUser.getSecretKey())
                    .qrCode(qrCode)
                    .build();
        } catch (Exception e){
            throw new MFAServerAppException("Exception while registering the user", e);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The TOTP Manager is responsible for generating the secret key and QR code. Let’s create the beans for this. By default, the secret generator will generate 32 32-byte secret keys. it can be overridden by passing a constructor argument.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Bean
    public SecretGenerator secretGenerator(){
        return new DefaultSecretGenerator();
    }

    @Bean
    public QrGenerator qrGenerator(){
        return new ZxingPngQrGenerator();
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;TOTP Manager Implementation. We create a QR code with all the required details for the TOTP generation. Below QR code below contains the secret, number of digits, period, and algorithm. These details help the Authenticator app generate a TOTP that matches the server.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
public String generateSecretKey() {
    return secretGenerator.generate(); // 32 Byte Secret Key
}

@Override
public String getQRCode(String secret) throws QrGenerationException {
    QrData qrData = new QrData.Builder().label("2FA Server")
            .issuer("Youtube 2FA Demo")
            .secret(secret)
            .digits(6)
            .period(30)
            .algorithm(HashingAlgorithm.SHA512)
            .build();

    return Utils.getDataUriForImage(qrGenerator.generate(qrData), qrGenerator.getImageMimeType());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now Registration endpoint is ready. Let’s try with UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhc17792ir4ldlpsf12f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhc17792ir4ldlpsf12f.png" alt="Registration UI with details keyed" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The below screenshot shows the QR code returned after successful registration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14z1mn88ssgp7grtm5j8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14z1mn88ssgp7grtm5j8.png" alt="After successful registration of the user" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mongo DB with User data persisted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpv7xookmr70zpxj2jn12.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpv7xookmr70zpxj2jn12.png" alt="user persistance" width="800" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;we have completed the registration successfully. Now user scans the QR code with the authenticator app to generate the one-time password. Let's create the login and verifyTotp endpoints.&lt;/p&gt;
&lt;h2&gt;
  
  
  Login endpoint Implementation
&lt;/h2&gt;

&lt;p&gt;The controller delegates the request to service and responds with a response.&lt;/p&gt;

&lt;p&gt;Here we respond with all the required parameters for UI to determine the user needs to be validated again on 2FA, user is validated, JWT, and message.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping(value = "/login", produces = "application/json")
    public ResponseEntity&amp;lt;?&amp;gt; login(@Validated @RequestBody LoginRequest loginRequest) {
        // Validate the user credentials and return the JWT / send redirect to MFA page
        try {//Get the user and Compare the password
            Authentication authentication = authenticationProvider.authenticate(
                    new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())
            );
            SecurityContextHolder.getContext().setAuthentication(authentication);
            User user = (User) authentication.getPrincipal();
            return ResponseEntity.ok(MfaVerificationResponse.builder()
                    .username(loginRequest.getUsername())
                    .tokenValid(Boolean.FALSE)
                    .authValid(Boolean.TRUE)
                    .mfaRequired(Boolean.TRUE)
                    .message("User Authenticated using username and Password")
                    .jwt("")
                    .build());

        } catch (Exception e){
            return ResponseEntity.ok(MfaVerificationResponse.builder()
                    .username(loginRequest.getUsername())
                    .tokenValid(Boolean.FALSE)
                    .authValid(Boolean.FALSE)
                    .mfaRequired(Boolean.FALSE)
                    .message("Invalid Credentials. Please try again.")
                    .jwt("")
                    .build());
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We are using an authentication provider from Spring Security that validates the user. Alternatively, you can directly validate the password and respond as we are going to implement JWT in the upcoming blog.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        Optional&amp;lt;User&amp;gt; userDetails = userRepository.findByUsername(username);
        if(userDetails.isPresent()){
            if (userDetails != null &amp;amp;&amp;amp; passwordEncoder.matches(password, userDetails.get().getPassword())) {
                return new UsernamePasswordAuthenticationToken(userDetails.get(), password);
            } else {
                throw new BadCredentialsException("Invalid password");
            }
        } else {
            throw new UsernameNotFoundException("Username Not Found");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s validate the login page using /login API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxv62a0x6p8gqdaax1vn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxv62a0x6p8gqdaax1vn8.png" alt="Login Screen with message for invalid credentials" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s enter valid credentials and it navigates us to the 2FA page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjdktc0g0pknqxllrek50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjdktc0g0pknqxllrek50.png" alt="User prompted for 2FA upon successful login" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows the login is working as expected. Let's move on to create the verifyTotp endpoint.&lt;/p&gt;
&lt;h2&gt;
  
  
  VerifyTotp Implementation
&lt;/h2&gt;

&lt;p&gt;The controller delegates the request to the service layer and responds back with the response from the service&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping("/verifyTotp")
public ResponseEntity&amp;lt;?&amp;gt; verifyTotp(@Validated @RequestBody MfaVerificationRequest request) {
    MfaVerificationResponse mfaVerificationResponse = MfaVerificationResponse.builder()
            .username(request.getUsername())
            .tokenValid(Boolean.FALSE)
            .message("Token is not Valid. Please try again.")
            .build();
    // Validate the OTP
    if(userService.verifyTotp(request.getTotp(), request.getUsername())){
        mfaVerificationResponse = MfaVerificationResponse.builder()
                .username(request.getUsername())
                .tokenValid(Boolean.TRUE)
                .message("Token is valid")
                .jwt("DUMMYTOKEN")
                .build();
    }
    return ResponseEntity.ok(mfaVerificationResponse);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The service layer makes use of a code verifier from samssteven.totp dependency to validate. User secret will be queried from DB using the username from the payload&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Override
public boolean verifyTotp(String code, String username) {
    User user = userRepository.findByUsername(username).get();
    return totpManager.verifyTotp(code, user.getSecretKey());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @Override
    public boolean verifyTotp(String code, String secret) {
        return myCodeVerifier.isValidCode(secret, code);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We will create a bean of it with the same values which was used for QR code generation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Code (TOTP) can be verified with time and the code generation algorithm. We will create the object of Time Provider and Code Generator as below. All the parameters must be the same as the QR code data.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Bean
    public CodeVerifier myCodeVerifier(){
        // Time
        TimeProvider timeProvider = new SystemTimeProvider();
        // Code Generator
        CodeGenerator codeGenerator = new DefaultCodeGenerator(HashingAlgorithm.SHA512, 6);
        DefaultCodeVerifier codeVerifier = new DefaultCodeVerifier(codeGenerator, timeProvider);
        codeVerifier.setTimePeriod(30);
        codeVerifier.setAllowedTimePeriodDiscrepancy(2);
        return  codeVerifier;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Let’s check this out from UI. I have entered the OTP generated from the authenticator app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4d1ftjsjrnr2ice29u3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr4d1ftjsjrnr2ice29u3.png" alt="key in TOTP from authenticator app" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon submission it successfully allowed me into the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc449lfbz491gau9ln6v4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc449lfbz491gau9ln6v4.png" alt="Home page after successful TOTP" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kudos!!! We have successfully implemented the TOTP as 2FA into our application. Please feel free to refer to the GitHub repo.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;
        MFAApplication
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Mfaapplication&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Application developed using Angular 14 and Bootstrap.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Components involved.&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Register&lt;/li&gt;
&lt;li&gt;TOTP&lt;/li&gt;
&lt;li&gt;Home Module&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/mfaserver" rel="noopener noreferrer"&gt;
        mfaserver
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Spring boot backend for MFA
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;MFA Server&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Application for 2FA demo.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;APIs Involved&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;login&lt;/li&gt;
&lt;li&gt;register&lt;/li&gt;
&lt;li&gt;verifyTotp&lt;/li&gt;
&lt;li&gt;confrim-email&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Dependencies&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;dev.samstevens.totp&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/mfaserver" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


</description>
      <category>security</category>
      <category>springboot</category>
      <category>angular</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Securing Your App: TOTP Authentication with Spring Boot and Angular — Part One — Overview &amp; Project Setup</title>
      <dc:creator>Anbumani</dc:creator>
      <pubDate>Sun, 31 Dec 2023 22:38:00 +0000</pubDate>
      <link>https://dev.to/amailath/securing-your-app-totp-authentication-with-spring-boot-and-angular-part-one-overview-project-setup-1f3f</link>
      <guid>https://dev.to/amailath/securing-your-app-totp-authentication-with-spring-boot-and-angular-part-one-overview-project-setup-1f3f</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Gpv0q-kwvJY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is TOTP?
&lt;/h2&gt;

&lt;p&gt;TOTP stands for Time-based One-Time Passwords and is a common form of two-factor authentication (2FA). Unique numeric passwords are generated with a standardized algorithm that uses the current time as an input. The time-based passwords are available offline and provide user-friendly, increased account security when used as a second factor.&lt;/p&gt;

&lt;p&gt;TOTP is also known as app-based authentication, software tokens, or soft tokens. Authentication apps like Microsoft Authenticator and Google Authenticator support the TOTP standard.&lt;/p&gt;

&lt;h2&gt;
  
  
  When TOTP?
&lt;/h2&gt;

&lt;p&gt;Imagine a secure system that combines something you know (like a password) with something you have (a device generating a one-time password). That’s where TOTP comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does TOTP work?
&lt;/h2&gt;

&lt;p&gt;When the user registers into our application system will generate a secret key and that will be stored in DB. The system will generate a QR code that combines the Algorithm, number of digits, and period that will be used by the server to generate the TOTP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ybhnjvsoiv2llsngzrr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ybhnjvsoiv2llsngzrr.jpg" alt="How TOTP QR code generated and user registration" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Upon login, the user will provide the credentials and validate. As a next step, they will be prompted for OTP. This will be generated by the authenticator application, this will be validated by the server using the time bucket the OTP is entered.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdqgej5rb2qynrta2obz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdqgej5rb2qynrta2obz.png" alt="TOTP validation" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Project:
&lt;/h2&gt;

&lt;p&gt;We will implement the Backend server in Spring Boot and Mongo DB as a Persistence layer. Angular 14 is our Front end which will connect to the backend over rest endpoints. We will be using “dev.samstevens.totp” to generate and verify TOTP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdop2vc5pf2f7j7c065b4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdop2vc5pf2f7j7c065b4.jpg" alt="Arch High-level" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  End-Point Implementation Overview:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;/register&lt;/strong&gt;&lt;br&gt;
register endpoint will accept the registration details including the username and password as payload. It will check for user existence, if the user already exists then respond with a UserAlreadyExist exception, else Generate the Secret key, encode the password received, and persist the user details. Further, generate the QR code and add it to the response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydzcyn9f473c3ll5hmg4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fydzcyn9f473c3ll5hmg4.jpg" alt="/register workflow" width="800" height="655"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/verifyTotp&lt;/strong&gt;&lt;br&gt;
This endpoint accepts username and TOTP as payload. It will fetch the secret key with the username provided and pass it to the verify method of the “dev.samstevens.totp” code verifier. If the code is valid then it will generate the JWT and respond. Else it will respond as an Invalid Token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwu02abe9t98odtu3dm8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwu02abe9t98odtu3dm8.jpg" alt="/verifyTotp workflow" width="800" height="727"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/login&lt;/strong&gt;&lt;br&gt;
This endpoint will get the username and password as payload and validate with the AuthProvider. If the credentials are valid and the user opted for MFA then respond with MFA Required. Else generate the JWT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnleyko30u52imayfzqko.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnleyko30u52imayfzqko.jpg" alt="/login workflow" width="800" height="727"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Project Setup:
&lt;/h2&gt;

&lt;p&gt;Create a Spring Boot Project with the following dependencies,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-boot-starter-data-mongodb&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-boot-starter-mail&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-boot-starter-security&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;dev.samstevens.totp&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;totp&amp;lt;/artifactId&amp;gt;
   &amp;lt;version&amp;gt;1.7.1&amp;lt;/version&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-boot-starter-validation&amp;lt;/artifactId&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;spring-boot-devtools&amp;lt;/artifactId&amp;gt;
   &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
   &amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
  &amp;lt;/dependency&amp;gt;
  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
   &amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
  &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;application.yaml&lt;/p&gt;

&lt;p&gt;&lt;code&gt;spring:&lt;br&gt;
  application:&lt;br&gt;
    name: mfa-server&lt;br&gt;
  data:&lt;br&gt;
    mongodb:&lt;br&gt;
      host: localhost&lt;br&gt;
      port: 27017&lt;br&gt;
      database: mfa-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create a websecurity configuration class for all endpoints. Also, create a bean if BCryptPasswordEncoder.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`@EnableWebSecurity
@Configuration
public class AppSecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain defaultFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .cors(cors-&amp;gt; cors.disable())
                .csrf(csrf-&amp;gt; csrf.disable())
                .sessionManagement(session-&amp;gt; session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .authorizeHttpRequests(auth-&amp;gt; auth
                        .requestMatchers("/error**","/register**","/login**","/verifyTotp**").permitAll()
                        .anyRequest().authenticated()
                )
               .build();
    }
}`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a User Entity. This stores the user details, credentials, and roles.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`@Document(collection = "users")
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
    @Id
    private String id;
    @Indexed
    @NotBlank
    private String username;
    private String password;
    boolean mfaEnabled;
    @JsonIgnore
    private String secretKey;
    private String firstName;
    private String lastName;
    private boolean active;
    @DBRef
    private Set&amp;lt;Role&amp;gt; roles = new HashSet&amp;lt;&amp;gt;();
}`

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create UserRepository.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`@Repository
public interface UserRepository extends MongoRepository&amp;lt;User, Long&amp;gt; {
    Optional&amp;lt;User&amp;gt; findByUsername(String username);
}`

Create a Service that Helps us Register and Verify Totp

`public interface UserService {
    MfaTokenData registerUser(User user) throws UserAlreadyExistException, QrGenerationException;
    boolean verifyTotp(final String code,String username);
}`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a Controller exposing the endpoints for /register, /login, and /verifyTotp.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We will look into the Implementation in our next blog.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/amailath" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1245595%2Fa5bd1fa7-a13b-4b8d-98c3-215b5a8e33bf.jpg" alt="amailath"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/amailath/securing-your-app-totp-authentication-with-spring-boot-and-angular-part-two-implementation-demo-594o" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Securing Your App: TOTP Authentication with Spring Boot and Angular — Part Two— Implementation &amp;amp; Demo&lt;/h2&gt;
      &lt;h3&gt;Anbumani ・ Dec 31 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#security&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#springboot&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#mongodb&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;br&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Angular Project Setup
&lt;/h2&gt;

&lt;p&gt;Create an angular project and include Bootstrap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`"styles": [
"node_modules/bootstrap/scss/bootstrap.scss" ,
"src/styles.scss"
],
"scripts": [
"node_modules/bootstrap/dist/js/bootstrap.bundle.js"
]
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a client service that connects with the backend over the rest endpoints.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`@Injectable({
  providedIn: 'root'
})
export class AuthClientService {

  constructor(private http: HttpClient) { }

  public login(payload: string): Observable&amp;lt;MfaVerificationResponse&amp;gt; {
    const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type':  'application/json'
      })
    };
    return this.http.post&amp;lt;MfaVerificationResponse&amp;gt;(
      environment.apiUrl + '/login', payload, httpOptions
    );
  }

  public verifyTotp(payload: MfaVerificationRequest): Observable&amp;lt;MfaVerificationResponse&amp;gt; {
    return this.http.post&amp;lt;MfaVerificationResponse&amp;gt;(
      environment.apiUrl + '/verifyTotp', payload
    );
  }

  public register(
    payload: string
  ): Observable&amp;lt;string&amp;gt; {
    return this.http.post(
      environment.apiUrl + '/register',payload,
      { responseType: 'text' }
    );
  }
}
`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a Login, Register components as per your wish, and connect them with the client. You can refer to my implementation from below GitHub.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/amaialth" rel="noopener noreferrer"&gt;
        amaialth
      &lt;/a&gt; / &lt;a href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;
        MFAApplication
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Mfaapplication&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Application developed using Angular 14 and Bootstrap.&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Components involved.&lt;/h2&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Login&lt;/li&gt;
&lt;li&gt;Register&lt;/li&gt;
&lt;li&gt;TOTP&lt;/li&gt;
&lt;li&gt;Home Module&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/amaialth/MFAApplication" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Check out the complete code implementation here&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/amailath" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1245595%2Fa5bd1fa7-a13b-4b8d-98c3-215b5a8e33bf.jpg" alt="amailath"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/amailath/securing-your-app-totp-authentication-with-spring-boot-and-angular-part-two-implementation-demo-594o" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Securing Your App: TOTP Authentication with Spring Boot and Angular — Part Two— Implementation &amp;amp; Demo&lt;/h2&gt;
      &lt;h3&gt;Anbumani ・ Dec 31 '23&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#security&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#springboot&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#angular&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#mongodb&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>security</category>
      <category>springboot</category>
      <category>angular</category>
      <category>mongodb</category>
    </item>
  </channel>
</rss>
