{"id":122409,"date":"2024-05-20T10:07:50","date_gmt":"2024-05-20T07:07:50","guid":{"rendered":"https:\/\/www.javacodegeeks.com\/?p=122409"},"modified":"2024-05-20T10:07:53","modified_gmt":"2024-05-20T07:07:53","slug":"rest-api-security-with-spring-security-jwt-token-signing","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html","title":{"rendered":"REST API Security with Spring Security JWT Token Signing"},"content":{"rendered":"<p>Securing REST APIs is important in today&#8217;s web development, especially with microservices becoming more common. A popular way to do this is with JSON Web Tokens (JWT). Spring Security helps with JWT-based authentication and authorization in Spring applications. In this article, we&#8217;ll see how to create a Spring Security key for signing JWT tokens and use it in a Spring Boot app to secure REST APIs.<\/p>\n<h2 class=\"wp-block-heading\">1. Set up a Spring Boot Application<\/h2>\n<p>Let&#8217;s begin by creating a new Spring Boot application by either using Spring Initializr (<a href=\"https:\/\/start.spring.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/start.spring.io\/<\/a>) or your preferred IDE to create a new project with the necessary dependencies:<\/p>\n<ul class=\"wp-block-list\">\n<li>Spring Web<\/li>\n<li>Spring Security<\/li>\n<\/ul>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/springinitializrjwt.png\"><img decoding=\"async\" width=\"1024\" height=\"612\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/springinitializrjwt-1024x612.png\" alt=\"Fig 1: Generate a spring boot project with the dependencies (spring security and spring web) for jthe wt token example\" class=\"wp-image-122809\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/springinitializrjwt-1024x612.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/springinitializrjwt-300x179.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/springinitializrjwt-768x459.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/springinitializrjwt.png 1440w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><figcaption class=\"wp-element-caption\">Fig 1: Generate a spring boot project with the dependencies (spring security and spring web) for the jwt token example<\/figcaption><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">2. Add JSON Web Token Dependencies<\/h2>\n<p>In the <code>pom.xml<\/code> file of the project (if using Maven), add the following dependencies for JWT token handling:<\/p>\n<pre class=\"brush:xml\">\n        &lt;dependency&gt;\n            &lt;groupId&gt;io.jsonwebtoken&lt;\/groupId&gt;\n            &lt;artifactId&gt;jjwt-api&lt;\/artifactId&gt;\n            &lt;version&gt;0.12.5&lt;\/version&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupId&gt;io.jsonwebtoken&lt;\/groupId&gt;\n            &lt;artifactId&gt;jjwt-impl&lt;\/artifactId&gt;\n            &lt;version&gt;0.12.5&lt;\/version&gt;\n            &lt;scope&gt;runtime&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n        &lt;dependency&gt;\n            &lt;groupId&gt;io.jsonwebtoken&lt;\/groupId&gt;\n            &lt;artifactId&gt;jjwt-jackson&lt;\/artifactId&gt;\n            &lt;version&gt;0.12.5&lt;\/version&gt;\n            &lt;scope&gt;runtime&lt;\/scope&gt;\n        &lt;\/dependency&gt;\n<\/pre>\n<h2 class=\"wp-block-heading\">3. Create JWT Utility Class<\/h2>\n<p>Next, create a utility class for handling JWT operations. This class will be responsible for generating JWT tokens and verifying them. Below is a simple implementation of the JWT utility class:<\/p>\n<pre class=\"brush:java\">\n@Component\npublic class JwtUtil {\n\n    @Value(\"${jcg.jwt.secret}\")\n    private String jwtSecret;\n\n    public String generateToken(UserDetails userDetails) {\n        Map&lt;String, Object&gt; claims = new HashMap&lt;&gt;();\n        claims.put(\"Authorities\", userDetails.getAuthorities());\n\n        return Jwts.builder()\n                .setClaims(claims)\n                .setSubject(userDetails.getUsername())\n                .setIssuedAt(new Date())\n                .setExpiration(new Date(System.currentTimeMillis() + 86400))\n                .signWith(getSignInKey(), SignatureAlgorithm.HS256)\n                .compact();\n    }\n\n    public String extractUsername(String token) {\n        return extractClaim(token, Claims::getSubject);\n    }\n\n    public &lt;T&gt; T extractClaim(String token, Function&lt;Claims, T&gt; claimsResolver) {\n        final Claims claims = extractAllClaims(token);\n        return claimsResolver.apply(claims);\n    }\n\n    private Claims extractAllClaims(String token) {\n        \n        return Jwts.parser()\n                .setSigningKey(getSignInKey())\n                .build()\n                .parseClaimsJws(token)\n                .getBody();\n    }\n\n    public boolean validateToken(String token, UserDetails userDetails) {\n        final String username = extractUsername(token);\n        return (username.equals(userDetails.getUsername()) &amp;&amp; !isTokenExpired(token));\n    }\n\n    private boolean isTokenExpired(String token) {\n        return extractExpiration(token).before(new Date());\n    }\n\n    private Date extractExpiration(String token) {\n        return extractClaim(token, Claims::getExpiration);\n    }\n    \n    private SecretKey getSignInKey() {\n        byte[] keyBytes = Decoders.BASE64.decode(jwtSecret);\n        return Keys.hmacShaKeyFor(keyBytes);\n    }\n}\n\n<\/pre>\n<p>The code block above represents a class named <code>JwtUtil<\/code> which is responsible for handling JWT (JSON Web Token) operations within our application. Here is a break down its functionalities:<\/p>\n<ul class=\"wp-block-list\">\n<li>The class injects the JWT secret key from the <code>application.properties<\/code> file using the <code>@Value<\/code> annotation.<\/li>\n<li><strong>Token Generation<\/strong>: The <code>generateToken<\/code> method creates a JWT token based on the provided <code>UserDetails<\/code>. It sets the <strong>subject<\/strong> (username), <strong>issue date<\/strong>, <strong>expiration date,<\/strong> and signs the token using the HMAC SHA-256 algorithm with the secret key.<\/li>\n<li><strong><code>extractUsername<\/code> Method<\/strong>: This method takes a JWT token as input and returns the username extracted from the token&#8217;s subject claim. It delegates the claim extraction process to the <code>extractClaim<\/code> method, passing in the token and a function reference (<code>Claims::getSubject<\/code>) to extract the subject claim.<\/li>\n<li><strong><code>extractClaim<\/code> Method<\/strong>: This generic method takes a JWT token and a <code>Function<\/code> that resolves a specific claim from the token&#8217;s <code>Claims<\/code> object. It first extracts all claims from the token by invoking the <code>extractAllClaims<\/code> method. Then, it applies the provided <code>claimsResolver<\/code> function to the <code>Claims<\/code> object to extract the desired claim.<\/li>\n<li><strong><code>extractAllClaims<\/code> Method<\/strong>: This method is responsible for parsing the JWT token, verifying its signature using the provided signing key, and extracting all claims from the token&#8217;s body. It uses the <code>Jwts.parser()<\/code> method to create a parser instance, sets the signing key with <code>setSigningKey(getSignInKey())<\/code>, and then parses the token with <code>parseClaimsJws(token)<\/code>.<\/li>\n<li><strong>Secret Key Retrieval<\/strong>: The <code>getSignInKey<\/code> method retrieves the secret key for signing and verifying JWT tokens. It decodes the base64-encoded secret key obtained from the <code>application.properties<\/code> file and converts it into a <code>SecretKey<\/code> object.<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\">3.1 Generate and Set JWT Secret Key<\/h3>\n<p>Producing a strong secret key is essential to ensure the security of JWT tokens. This entails generating an HMAC hash string consisting of 256 bits and configuring it as the JWT secret within the <code>application.properties<\/code> file. The online tool generator located at <a href=\"https:\/\/www.devglan.com\/online-tools\/hmac-sha256-online?ref=blog.tericcabrel.com\">devglan.com\/online-tools<\/a> can generate an HMAC hash string of 256 bits.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<h4 class=\"wp-block-heading\">3.1.1 Set JWT Secret in application.properties<\/h4>\n<p>Once the secret key is generated, it needs to be set in the <code>application.properties<\/code> file of the Spring Boot application:<\/p>\n<pre class=\"brush:plain\">\njcg.jwt.secret=YOUR_GENERATED_SECRET_KEY\n<\/pre>\n<p>Replace <code>YOUR_GENERATED_SECRET_KEY<\/code> with the generated HMAC hash string obtained earlier. <\/p>\n<h3 class=\"wp-block-heading\">3.2 Implementing Authentication Token Filter<\/h3>\n<p>Next, let&#8217;s implement an Authentication Token Filter which is crucial for securing REST endpoints with JWT tokens. Below is an example of an authentication token filter:<\/p>\n<pre class=\"brush:java\">\n@Component\npublic class JwtRequestFilter extends OncePerRequestFilter {\n\n    @Autowired\n    private JwtUtil jwtUtil;\n\n    @Autowired\n    private UserDetailsService userDetailsService;\n\n    @Override\n    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)\n            throws ServletException, IOException {\n\n        final String authorizationHeader = request.getHeader(\"Authorization\");\n\n        String username = null;\n        String jwt = null;\n\n        if (authorizationHeader != null &amp;&amp; authorizationHeader.startsWith(\"Bearer \")) {\n            jwt = authorizationHeader.substring(7);\n            username = jwtUtil.extractUsername(jwt);\n        }\n\n        if (username != null &amp;&amp; SecurityContextHolder.getContext().getAuthentication() == null) {\n\n            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);\n\n            if (jwtUtil.validateToken(jwt, userDetails)) {\n\n                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =\n                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());\n                usernamePasswordAuthenticationToken\n                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));\n                \n                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);\n            }\n        }\n        filterChain.doFilter(request, response);\n    }\n}\n<\/pre>\n<p>This filter intercepts incoming requests, extracts JWT tokens from the request header, validates them, and sets up authentication in the Spring Security context if the token is valid.<\/p>\n<h2 class=\"wp-block-heading\">4. Configure Spring Security<\/h2>\n<p>Next, configure Spring Security to use JWT for authentication. Create a <code>SecurityConfig<\/code> class and configure it as follows:<\/p>\n<pre class=\"brush:java\">\n@Configuration\n@EnableWebSecurity\npublic class SecurityConfig {\n\n    private static final String ADMIN = \"ADMIN\";\n    private static final String USER = \"USER\";\n\n    @Bean\n    public JwtRequestFilter jwtRequestFilter() {\n        return new JwtRequestFilter();\n    }\n\n    @Bean\n    public DaoAuthenticationProvider authenticationProvider() throws Exception {\n        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();\n        authProvider.setUserDetailsService(userDetailsService());\n        authProvider.setPasswordEncoder(passwordEncoder());\n\n        return authProvider;\n    }\n\n    @Bean\n    public SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {\n        http.csrf(AbstractHttpConfigurer::disable)\n                .cors(AbstractHttpConfigurer::disable)\n                .authorizeHttpRequests(req -&gt; req\n                .requestMatchers(\"\/admin\/**\").hasRole(ADMIN)\n                .requestMatchers(\"\/user\/**\").hasAnyRole(USER, ADMIN)\n                .requestMatchers(\"\/authenticate\")\n                .permitAll()\n                .anyRequest()\n                .authenticated())\n                .sessionManagement(session -&gt; session.sessionCreationPolicy(STATELESS))\n                .authenticationProvider(authenticationProvider())\n                .addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);\n\n        return http.build();\n    }\n\n    @Bean\n    public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {\n        return authConfig.getAuthenticationManager();\n    }\n\n    @Bean\n    public PasswordEncoder passwordEncoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Bean\n    public UserDetailsService userDetailsService() throws Exception {\n        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();\n        manager.createUser(User\n                .withUsername(\"thomas\")\n                .password(encoder().encode(\"paine\"))\n                .roles(ADMIN).build());\n        manager.createUser(User\n                .withUsername(\"bill\")\n                .password(encoder().encode(\"withers\"))\n                .roles(USER).build());\n        return manager;\n    }\n\n    @Bean\n    public PasswordEncoder encoder() {\n        return new BCryptPasswordEncoder();\n    }\n\n    @Bean\n    public CorsFilter corsFilter() {\n        UrlBasedCorsConfigurationSource source\n                = new UrlBasedCorsConfigurationSource();\n        CorsConfiguration config = new CorsConfiguration();\n        config.setAllowCredentials(true);\n        config.addAllowedOrigin(\"*\");\n        config.addAllowedHeader(\"*\");\n        config.addAllowedMethod(\"*\");\n        source.registerCorsConfiguration(\"\/**\", config);\n        return new CorsFilter(source);\n    }\n}\n\n<\/pre>\n<p>This code block configures security settings for the application using Spring Security. Let&#8217;s break down its functionalities:<\/p>\n<ul class=\"wp-block-list\">\n<li>The <code>jwtRequestFilter<\/code> method defines a bean for the <code>JwtRequestFilter<\/code> class. This filter intercepts incoming requests, extracts JWT tokens, and authenticates them.<\/li>\n<li><strong>DaoAuthenticationProvider Bean<\/strong>: The <code>authenticationProvider<\/code> method defines a bean for the <code>DaoAuthenticationProvider<\/code> class. This provider authenticates users based on the provided user details service and password encoder.<\/li>\n<li><strong>SecurityFilterChain Bean<\/strong>: The <code>securityFilterChain<\/code> method sets up authorization rules based on request matchers and roles.\n<ul class=\"wp-block-list\">\n<li><strong>Authorization Rules<\/strong>: The <code>.authorizeHttpRequests()<\/code> method specifies authorization rules for different types of requests:\n<ul class=\"wp-block-list\">\n<li>Requests to <code>\/admin\/**<\/code> endpoints require the <code>ADMIN<\/code> role.<\/li>\n<li>Requests to <code>\/user\/**<\/code> endpoints require either the <code>USER<\/code> or <code>ADMIN<\/code> role.<\/li>\n<li>Requests to <code>\/authenticate<\/code> endpoint are permitted without authentication (permit all).<\/li>\n<li>All other requests (<code>anyRequest()<\/code>) require authentication.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Session Management<\/strong>: Session management is configured to be stateless (<code>sessionCreationPolicy(STATELESS)<\/code>), meaning no server-side session will be created or used for storing user authentication state.<\/li>\n<\/ul>\n<\/li>\n<li><strong>AuthenticationManager Bean<\/strong>: The <code>authenticationManager<\/code> method defines a bean for the <code>AuthenticationManager<\/code> interface. It retrieves the authentication manager from the authentication configuration.<\/li>\n<li><strong>UserDetailsService Bean<\/strong>: The <code>userDetailsService<\/code> method defines an in-memory user store using <code>InMemoryUserDetailsManager<\/code>. We create two users with different roles: an <code>ADMIN<\/code> user with username &#8220;<strong>thomas<\/strong>&#8221; and a <code>USER<\/code> user with username &#8220;<strong>bill<\/strong>&#8220;. <\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\">4.1 Custom UserDetails Implementation<\/h3>\n<p>Spring Security relies on the <code>UserDetails<\/code> interface for both authentication and authorization purposes. Below is an implementation of the <code>User<\/code> class which implements the <code>UserDetails<\/code> interface for authentication and authorization:<\/p>\n<pre class=\"brush:java\">\npublic class User implements UserDetails {\n\n    private int id;\n    private String username;\n    private String password;\n    private Collection&lt;? extends GrantedAuthority&gt; authorities;\n\n    public User() {\n    }\n\n    public User(String username, String password, Collection&lt;? extends GrantedAuthority&gt; authorities) {\n        this.password = password;\n        this.username = username;\n        this.authorities = authorities;\n    }\n\n    public User(String username, Collection&lt;String&gt; authorities) {\n        this.username = username;\n        this.authorities = authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());\n    }\n\n    \/\/ UserDetails interface methods\n    @Override\n    public String getUsername() {\n        return username;\n    }\n\n    @Override\n    public String getPassword() {\n        return password;\n    }\n\n    @Override\n    public Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {\n        return authorities;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return true;\n    }\n\n    @Override\n    public boolean isCredentialsNonExpired() {\n        return true;\n    }\n\n    @Override\n    public boolean isAccountNonLocked() {\n        return true;\n    }\n\n    @Override\n    public boolean isAccountNonExpired() {\n        return true;\n    }\n\n}\n<\/pre>\n<p>The <code>User<\/code> class implements the <code>UserDetails<\/code> interface and represents a user in the application. It includes fields for username, password, and authorities. The <code>UserDetails<\/code> interface is a core interface in Spring Security used for user authentication and authorization. It represents a principal (user) in the system and provides methods for accessing user details and authorities.<\/p>\n<p><code>getAuthorities()<\/code> method returns the authorities (roles) granted to the user. <code>getPassword()<\/code> and <code>getUsername()<\/code> methods return the password and username of the user, respectively. <code>isAccountNonExpired()<\/code> <code>isAccountNonLocked()<\/code>, <code>isCredentialsNonExpired()<\/code>, <code>isEnabled()<\/code> methods return <code>true<\/code> if the user account is not expired, not locked, credentials are not expired, and the user is enabled, respectively.<\/p>\n<h2 class=\"wp-block-heading\">5. Integration with Spring Boot<\/h2>\n<p>Finally, Let&#8217;s integrate the JWT utility and Spring Security configurations with our Spring Boot application. Here&#8217;s a basic example of a REST controller for authentication:<\/p>\n<pre class=\"brush:java\">\n@RestController\npublic class AuthController {\n\n    @Autowired\n    private AuthenticationManager authenticationManager;\n\n    @Autowired\n    private JwtUtil jwtUtil;\n\n    @Autowired\n    private UserDetailsService userDetailsService;\n\n    @PostMapping(\"\/authenticate\")\n    public ResponseEntity createAuthenticationToken(@RequestBody AuthRequest authRequest) throws Exception {\n        try {\n            authenticationManager.authenticate(\n                    new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())\n            );\n        } catch (BadCredentialsException e) {\n            throw new Exception(\"Incorrect username or password\", e);\n        }\n\n        \n        final UserDetails userDetails = userDetailsService\n                .loadUserByUsername(authRequest.getUsername());\n\n        final String jwt = jwtUtil.generateToken(userDetails);\n\n        return ResponseEntity.ok(new AuthResponse(jwt));\n    }\n    \n    @GetMapping(\"\/auth\/details\")\n    public UserDetails getDetails(){\n        var detail = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();\n        return detail;\n    }\n\n}\n\n<\/pre>\n<p>This block of code defines an <code>AuthController<\/code> class responsible for handling authentication-related HTTP requests in the application.<\/p>\n<ul class=\"wp-block-list\">\n<li>The controller class autowires the dependencies (<code>AuthenticationManager<\/code>, <code>JwtUtil<\/code>, and <code>UserDetailsService<\/code>) required for authentication and token generation.<\/li>\n<li><strong>createAuthenticationToken Method<\/strong>: This method handles POST requests to <code>\/authenticate<\/code> endpoint. It attempts to authenticate the user by passing the provided credentials to the <code>AuthenticationManager<\/code>. If authentication is successful, it generates a JWT token using <code>JwtUtil<\/code> and returns it in the response body.<\/li>\n<li><strong>getDetails Method<\/strong>: This method handles GET requests to <code>\/auth\/details<\/code> endpoint. It retrieves the authenticated user&#8217;s details (such as username, authorities) from the <code>SecurityContextHolder<\/code>.<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\">5.1 Securing REST Endpoints<\/h3>\n<pre class=\"brush:java\">\n@RestController\npublic class SimpleController {\n    \n    @RolesAllowed(\"ADMIN\")\n    @GetMapping(\"\/admin\")\n    public ResponseEntity&lt;String&gt; testAdmin() {\n        return ResponseEntity.ok(\"This is the Admin role\");\n    }\n\n    @RolesAllowed(\"USER\")\n    @GetMapping(\"\/user\")\n    public ResponseEntity&lt;String&gt; testUser() {\n        return ResponseEntity.ok(\"This is the User role\");\n    }\n}\n<\/pre>\n<p>This <code>SimpleController<\/code> class defines endpoints that are accessible only to users with specific roles. It enforces role-based access control (RBAC), ensuring that certain operations can only be performed by users with the appropriate roles.<\/p>\n<ul class=\"wp-block-list\">\n<li><strong>testAdmin Method<\/strong>: This method handles GET requests to the <code>\/admin<\/code> endpoint. It is annotated with <code>@RolesAllowed(\"ADMIN\")<\/code>, which specifies that only users with the role &#8220;<strong>ADMIN<\/strong>&#8221; are allowed to access this endpoint. <\/li>\n<li><strong>testUser Method<\/strong>: This method handles GET requests to the <code>\/user<\/code> endpoint. Similar to the <code>testAdmin<\/code> method, it is annotated with <code>@RolesAllowed(\"USER\")<\/code>, indicating that only users with the role &#8220;<strong>USER<\/strong>&#8221; can access this endpoint.<\/li>\n<\/ul>\n<p>To verify the functionality of the application, we can utilize POSTMAN to send a request to <strong>http:\/\/localhost:8080\/authenticate<\/strong> and acquire a JWT token.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/authenticate-endpoint.png\"><img decoding=\"async\" width=\"1024\" height=\"602\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/authenticate-endpoint-1024x602.png\" alt=\"\" class=\"wp-image-122829\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/authenticate-endpoint-1024x602.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/authenticate-endpoint-300x176.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/authenticate-endpoint-768x451.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/authenticate-endpoint.png 1098w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<p>Next, proceed by setting the request header with the JWT key and verify if <a href=\"http:\/\/localhost:8080\/auth\/me\">http:\/\/localhost:8080\/auth\/details<\/a> functions correctly.<\/p>\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/requestheaderwithjwt-1.png\"><img decoding=\"async\" width=\"1024\" height=\"718\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/requestheaderwithjwt-1-1024x718.png\" alt=\"\" class=\"wp-image-122833\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/requestheaderwithjwt-1-1024x718.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/requestheaderwithjwt-1-300x210.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/requestheaderwithjwt-1-768x539.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/requestheaderwithjwt-1.png 1089w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<p>Now, let&#8217;s verify if we can access the <a href=\"http:\/\/localhost:8080\/user\">http:\/\/localhost:8080\/user<\/a> endpoint:<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/userrole.png\"><img decoding=\"async\" width=\"1024\" height=\"614\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/userrole-1024x614.png\" alt=\"\" class=\"wp-image-122835\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/userrole-1024x614.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/userrole-300x180.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/userrole-768x461.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/userrole.png 1084w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n<p>If a user with the <strong>USER<\/strong> role attempts to access the <code>\/admin<\/code> endpoint, Spring Security will deny the request, and the user will receive an HTTP status code indicating access forbidden (403).<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/jwt-admin-deny.png\"><img decoding=\"async\" width=\"1024\" height=\"564\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/jwt-admin-deny-1024x564.png\" alt=\"\" class=\"wp-image-122859\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/jwt-admin-deny-1024x564.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/jwt-admin-deny-300x165.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/jwt-admin-deny-768x423.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/jwt-admin-deny.png 1047w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\">6. Conclusion<\/h2>\n<p>In this article, we&#8217;ve learned how to generate a key to sign JWT tokens and include it in a Spring Boot application for security. We also saw how to secure specific endpoints based on user roles. By using Spring Security to sign a JWT token, we greatly improve the security of our application.<\/p>\n<h2 class=\"wp-block-heading\">7. Download the Source Code<\/h2>\n<p>This was an article on how to create a spring security key to sign JWT Token to Secure REST APIs.<\/p>\n<div class=\"download\"><strong>Download<\/strong><br \/>\nYou can download the full source code of this example here: <a href=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2024\/05\/securitykeyforjwt.zip\"><strong>Create Spring Security Key to Sign JWT Token to Secure REST APIs<\/strong><\/a>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Securing REST APIs is important in today&#8217;s web development, especially with microservices becoming more common. A popular way to do this is with JSON Web Tokens (JWT). Spring Security helps with JWT-based authentication and authorization in Spring applications. In this article, we&#8217;ll see how to create a Spring Security key for signing JWT tokens and &hellip;<\/p>\n","protected":false},"author":128888,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[1373,2644,2643,1289,2645,125],"class_list":["post-122409","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-authentication","tag-authorization","tag-json-web-tokens","tag-jwt","tag-rest-api-security","tag-spring-security"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>REST API Security with Spring Security JWT Token Signing - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Learn to secure REST APIs by creating a Spring Security key to sign a JWT token in this comprehensive tutorial.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"REST API Security with Spring Security JWT Token Signing - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Learn to secure REST APIs by creating a Spring Security key to sign a JWT token in this comprehensive tutorial.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:author\" content=\"https:\/\/web.facebook.com\/omos.aziegbe\" \/>\n<meta property=\"article:published_time\" content=\"2024-05-20T07:07:50+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-05-20T07:07:53+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Omozegie Aziegbe\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/OAziegbe\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Omozegie Aziegbe\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html\"},\"author\":{\"name\":\"Omozegie Aziegbe\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/7d3eac6e45542536e961129ae0fb453e\"},\"headline\":\"REST API Security with Spring Security JWT Token Signing\",\"datePublished\":\"2024-05-20T07:07:50+00:00\",\"dateModified\":\"2024-05-20T07:07:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html\"},\"wordCount\":1321,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"Authentication\",\"authorization\",\"JSON Web Tokens\",\"JWT\",\"REST API security\",\"Spring Security\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html\",\"name\":\"REST API Security with Spring Security JWT Token Signing - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2024-05-20T07:07:50+00:00\",\"dateModified\":\"2024-05-20T07:07:53+00:00\",\"description\":\"Learn to secure REST APIs by creating a Spring Security key to sign a JWT token in this comprehensive tutorial.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/rest-api-security-with-spring-security-jwt-token-signing.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"REST API Security with Spring Security JWT Token Signing\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/7d3eac6e45542536e961129ae0fb453e\",\"name\":\"Omozegie Aziegbe\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/cropped-jcg_profile_pic-96x96.jpg\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/cropped-jcg_profile_pic-96x96.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2023\\\/12\\\/cropped-jcg_profile_pic-96x96.jpg\",\"caption\":\"Omozegie Aziegbe\"},\"description\":\"Omos Aziegbe is a technical writer and web\\\/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.\",\"sameAs\":[\"https:\\\/\\\/web.facebook.com\\\/omos.aziegbe\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/omosaziegbe\\\/\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/OAziegbe\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/omozegie-aziegbe\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"REST API Security with Spring Security JWT Token Signing - Java Code Geeks","description":"Learn to secure REST APIs by creating a Spring Security key to sign a JWT token in this comprehensive tutorial.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html","og_locale":"en_US","og_type":"article","og_title":"REST API Security with Spring Security JWT Token Signing - Java Code Geeks","og_description":"Learn to secure REST APIs by creating a Spring Security key to sign a JWT token in this comprehensive tutorial.","og_url":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_author":"https:\/\/web.facebook.com\/omos.aziegbe","article_published_time":"2024-05-20T07:07:50+00:00","article_modified_time":"2024-05-20T07:07:53+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Omozegie Aziegbe","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/OAziegbe","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Omozegie Aziegbe","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html"},"author":{"name":"Omozegie Aziegbe","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/7d3eac6e45542536e961129ae0fb453e"},"headline":"REST API Security with Spring Security JWT Token Signing","datePublished":"2024-05-20T07:07:50+00:00","dateModified":"2024-05-20T07:07:53+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html"},"wordCount":1321,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["Authentication","authorization","JSON Web Tokens","JWT","REST API security","Spring Security"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html","url":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html","name":"REST API Security with Spring Security JWT Token Signing - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2024-05-20T07:07:50+00:00","dateModified":"2024-05-20T07:07:53+00:00","description":"Learn to secure REST APIs by creating a Spring Security key to sign a JWT token in this comprehensive tutorial.","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/rest-api-security-with-spring-security-jwt-token-signing.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"REST API Security with Spring Security JWT Token Signing"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/7d3eac6e45542536e961129ae0fb453e","name":"Omozegie Aziegbe","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2023\/12\/cropped-jcg_profile_pic-96x96.jpg","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2023\/12\/cropped-jcg_profile_pic-96x96.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2023\/12\/cropped-jcg_profile_pic-96x96.jpg","caption":"Omozegie Aziegbe"},"description":"Omos Aziegbe is a technical writer and web\/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.","sameAs":["https:\/\/web.facebook.com\/omos.aziegbe","https:\/\/www.linkedin.com\/in\/omosaziegbe\/","https:\/\/x.com\/https:\/\/twitter.com\/OAziegbe"],"url":"https:\/\/www.javacodegeeks.com\/author\/omozegie-aziegbe"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/122409","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/128888"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=122409"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/122409\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=122409"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=122409"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=122409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}