Tutorial. Spring Cloud API Gateway security with JSON Web Tokens

Поділитися
Вставка
  • Опубліковано 2 чер 2024
  • Would you like to enhance your software security? In this video tutorial, ORIL`s Lead Software Engineer, Ihor Kosandiak, shows you how to secure your microservices architecture with JSON Web Tokens (JWT). You’ll learn how to implement token authentication mechanisms to authorize and verify users in the system.
    For this tutorial, we use Java 11, Spring Boot, Spring Cloud, JWT, Maven, MacOS, and IntelliJ IDEA.
    0:00 Intro
    0:18 Project setup: Root module and Discovery service
    2:21 Config service module.
    4:33 Fetch connection data from Git.
    5:55 Create Auth service module.
    7:28 JWT builder implementation.
    10:39 Auth service functionality.
    15:07 Add bootstrap.yml to auth service.
    15:31 User service module.
    19:25 API Gateway service configuration.
    24:43 Filter implementation.
    26:17 Clearing things up, preparation for starting up the services.
    26:52 Postman request test One.
    29:07 Postman request test Two.
    👨‍💻 Read more about Spring Cloud Gateway security with JWT in our article oril.co/blog/spring-cloud-gat...
    Look for this project on GitHub github.com/oril-software/spri....
    Visit ORIL`s website oril.co
    Follow us:
    🔸 LinkedIn: / oril-software
    🔸 Facebook: orilsoftware
    🔸 Instagram: orilsoftware
    🔸 Twitter: / orilsoftware
    🔸 Behance: www.behance.net/oril-software
    #development #softwaredevelopment #tutorial #java #springboot #Springcloud #APIGateway #security
  • Наука та технологія

КОМЕНТАРІ • 64

  • @ofziton
    @ofziton 2 місяці тому +3

    This video is a tutorial that briefly explains the key parts, and it is very useful.
    Thank you very much.

    • @orilsoftware
      @orilsoftware  2 місяці тому

      Thank you for your feedback :)

  • @oksankamelnyk7903
    @oksankamelnyk7903 6 місяців тому +2

    Kudos to Ihor for another fantastic tutorial

  • @nursultanstanbek5191
    @nursultanstanbek5191 5 місяців тому +1

    very useful information. Thanks!

    • @orilsoftware
      @orilsoftware  4 місяці тому

      Hi! Great to know you find this tutorial useful :)

  • @kate123793
    @kate123793 9 місяців тому +1

    Great tutorial!

    • @orilsoftware
      @orilsoftware  9 місяців тому

      Hello! We’re happy to know that you find our tutorial valuable :)

  • @katerynamelnyk8678
    @katerynamelnyk8678 6 місяців тому

    saved, thanks 🤗

  • @gdhomelander6031
    @gdhomelander6031 10 днів тому +1

    Hvala gdje cuo i ne cuo

  • @shankaraec
    @shankaraec 8 місяців тому +1

    excellent

    • @orilsoftware
      @orilsoftware  8 місяців тому

      Hello! Great to know that you find this tutorial useful :)

  • @nilushadissanayaka5166
    @nilushadissanayaka5166 7 місяців тому +1

    YOU SAVED ME

    • @orilsoftware
      @orilsoftware  7 місяців тому +1

      Great to know this tutorial is useful for you :)

  • @nicholasboari
    @nicholasboari 4 місяці тому +1

    Thanks for the tutorial, where would my user database be located to validate it at the time of registration? In user-service or auth-service?

    • @orilsoftware
      @orilsoftware  4 місяці тому

      Hi! Thank you for your question. It is better to keep it in user-service, and allow your auth-service to fetch data from user-service(db) and validate at the time of registration.

  • @nikitaelokhin7529
    @nikitaelokhin7529 4 місяці тому +2

    Музыка на фоне зачетная 😎

  • @RN-jo8zt
    @RN-jo8zt 2 місяці тому +1

    Thank you for awesome tutorial. it's really helpful
    pls stop background music in future video🙂

    • @orilsoftware
      @orilsoftware  2 місяці тому

      Hi! Thank you for your feedback! Great to know you find this tutorial useful :)

  • @meoconhoccode
    @meoconhoccode 2 місяці тому +1

    thank you so much, but can you tell me how to write open point for pattern like /product/{id} ?

    • @orilsoftware
      @orilsoftware  Місяць тому

      Hi! When designing an API endpoint like /product/{id} in Spring Cloud API Gateway, you would typically want to define it in your API Gateway configuration. In Spring Cloud Gateway, you can define routes using RouteLocator or RouteDefinition.
      @Configuration
      public class GatewayConfig {
      @Bean
      public RouteLocator myRoutes(RouteLocatorBuilder builder) {
      return builder.routes()
      .route(p -> p
      .path("/product/{id}") // Define the path pattern
      .uri("your-product-service-url")) // Specify the URI of your product service
      .build();
      }
      }
      In this configuration:
      path("/product/{id}") specifies the path pattern. The {id} part is a path variable which can hold any value.
      uri("your-product-service-url") specifies the URI of the service that handles requests to this path.
      This route configuration will forward any requests matching the pattern /product/{id} to the specified product service.

  •  5 місяців тому

    Thank you for awesome tutorial. It was very clean and briefly explained.
    I have two questions. If we need to call another service using feign client how should we pass the token? I implemented a feign client request interceptor to add token to header before each request. Is that a good practice or not? Also if we need to communicate between microservices without user interaction what should we do? Can we get token from auth service for internal no user interaction requests? Thank you so much ❤

    • @orilsoftware
      @orilsoftware  5 місяців тому +1

      Hello!
      Passing Token to Another Service via Feign Client:
      In microservices architecture, using a Feign client request interceptor to add authentication tokens before each request is a common practice. This promotes a modular and reusable approach, encapsulating token logic for cleaner code.
      A centralized token management component is advisable for acquiring, refreshing, and propagating tokens across services. This ensures consistency and ease of maintenance, especially in handling token expiration and renewal.
      Security is paramount in token transmission. Always use HTTPS for encryption, and be vigilant about securing tokens during communication between microservices. Regularly update your token management strategy to align with evolving security best practices.
      Communicating Between Microservices without User Interaction:
      For internal microservice-to-microservice communication without user involvement, the OAuth2 client credentials grant type is widely adopted and secure. This involves each microservice having its own client ID and secret, acting as credentials to authenticate with the Authorization Server.
      Configure the Authorization Server to support the client credentials grant type and be aware of microservices' client IDs and secrets. This ensures that microservices can obtain the necessary tokens for secure communication.
      To enhance security, use short-lived tokens, minimizing risks in case of compromise. Always secure communication between microservices using HTTPS. Regularly review and update security protocols to align with industry best practices.

  • @irynazub5212
    @irynazub5212 11 місяців тому +2

    🔥🔥🔥

    • @orilsoftware
      @orilsoftware  11 місяців тому

      We are delighted that you find this video interesting!

  • @06p204
    @06p204 11 місяців тому +1

    Great video, thanks! Do you have a GitHub link to this project?

    • @orilsoftware
      @orilsoftware  11 місяців тому +1

      Hello! Yes, you can find this project here on GitHub github.com/oril-software/spring-cloud-api-gateway-jwt 🙂

  • @quangvan6338
    @quangvan6338 7 місяців тому +1

    Hi. I'm really glad to have such a helpful course like this. However, while following the video, I'm encountering a case: when making an API request, I only need to tick the Key Authorization in the Header. But in the value part, I leave it empty, without a token value. It still passes through securely. Can you help me resolve this issue? I'm extremely grateful.

    • @orilsoftware
      @orilsoftware  7 місяців тому

      Hello! Thank you for your feedback and question! That's the correct behavior as explained in this tutorial. If you examine the 'executeRequest' method in the 'GptRequestBuilder' class, you'll notice that the value for the authorization header is retrieved from the 'application.yml' file. Therefore, any 'Authorization' value passed via an API request will be ignored, and the valid 'Secret' will be obtained from the credentials in 'application.yml'. To change this, you will need to update the method parameters and accept the 'Secret' value from the request, then populate the request to ChatGPT with the 'Secret' value from the API request.

    • @quangvan6338
      @quangvan6338 7 місяців тому

      Im so grateful for your help. Thks so much.

  • @NikitaPorshennikov
    @NikitaPorshennikov 7 місяців тому +2

    Is this the right approach to application security? Can a user directly call services (e.g., user-service "/secured") and bypass token verification? How would roles and scopes work in this approach? Should role and scope checks also be performed in the API gateway?

    • @orilsoftware
      @orilsoftware  7 місяців тому +1

      Hi! Thank you for the question. The requests should only be sent to the API Gateway, and there shouldn't be a way to call the service directly. Roles and scopes should be validated in the API Gateway, and if validation is passed, the request should be directed to the appropriate microservice; otherwise, it should be rejected.

    • @AlmustaphaTukurUmar
      @AlmustaphaTukurUmar 5 місяців тому

      @@orilsoftware Pls. Can you share material for roles and scope authentication on Gateway?

  • @phucthinhnguyen1205
    @phucthinhnguyen1205 6 місяців тому

    Great video, but I have a question: If a user has dual roles as both a customer and an employee, and the customer sends a request with an authenticated token to access a resource associated with the employee, how can the API gateway differentiate permissions and allocate resources accordingly?

    • @orilsoftware
      @orilsoftware  6 місяців тому +1

      Hi! For this, you might consider Dynamic Resource Allocation. You can define dynamic resource allocation policies by:
      - Establishing policies that define how resources should be allocated based on the user's roles.
      - For each resource, define which roles are authorized to perform specific actions (e.g., read, write, delete).
      You can also combine this with the Contextual Authorization approach:
      - Implement contextual authorization logic in your API gateway or backend services.
      - When a request is received, the system should consider the user's roles and the requested resource to make an informed decision on whether the user has the necessary permissions.
      Or there is an option to implement this functionality using Middleware or Interceptor Mechanism
      - Use middleware or interceptor mechanisms in your API gateway to intercept incoming requests before they reach your microservices.
      - In the middleware, inspect the user's roles and decide resource allocation based on defined policies.
      By combining these approaches you can build a system that will allow you to handle multiple user roles and allocate system resources.

    • @phucthinhnguyen1205
      @phucthinhnguyen1205 6 місяців тому

      @@orilsoftware If I use Spring Security at the API Gateway, is that a bad idea?

    • @orilsoftware
      @orilsoftware  6 місяців тому

      @@phucthinhnguyen1205 Using Spring Security at the API Gateway is not a bad idea; in fact, it can be a very good one.
      While using Spring Security at the API Gateway is a good choice, it's important to ensure that your security design aligns with your specific use cases and requirements. Consider factors such as the types of authentication mechanisms needed, the scale of your microservices architecture, and the specific security features required for your application.

    • @phucthinhnguyen1205
      @phucthinhnguyen1205 6 місяців тому

      @@orilsoftware Let me ask you the last question: In each service, is it sufficient to have the main class and those related to it, or is it enough to have only one class for it? For example, if I have 2 services, Category and Product, with a one-to-many relationship, in the Product service, do I need to add a Category class to establish a relationship with Product, or is it enough to add an id attribute in the Product class that matches the id of Category?

    • @orilsoftware
      @orilsoftware  6 місяців тому

      @@phucthinhnguyen1205 The decision should be based on your specific requirements, the complexity of your domain model, and considerations related to maintainability and performance. Both approaches are valid, and the best choice depends on the context of your application. However, you might consider adding a Category class to Product service, because usually in the future as you develop an application, there are cases when you need more data to be available in the exact service, and having an entity for that data directly in the service you need it - will eliminate time for fetching this info from separate service. But again - it's really up to your decision.

  • @anhucnguyen8736
    @anhucnguyen8736 7 місяців тому +1

    Let's say my endpoints securityConfig class in the Authentication Service have a configuration like "ep-1/**" haveRole("SaleMan"). Then how the gateway service know the "ep-1/**" haveRole("SaleMan") configuration to intercept the request?

    • @orilsoftware
      @orilsoftware  6 місяців тому

      Hi! All the intercepting logic has to be implemented in the API Gateway service. It must validate all requests based on your custom logic and decide if a request should be passed or rejected.

    • @anhucnguyen8736
      @anhucnguyen8736 6 місяців тому

      @@orilsoftware it seems doesn't make sense. Because when the app is being scaled, the Gateway service needs to handle the RBAC config instead of the Auth service which is the main service that has responsible for security concerns.

    • @orilsoftware
      @orilsoftware  6 місяців тому

      @@anhucnguyen8736 There are different approaches to each issue. When working on a project, it's vital to carefully think about the different available approaches to find the best one :)

  • @rashadbs2010
    @rashadbs2010 Місяць тому

    thanks @oril .. i have one issue how to deal with cors error from frontend whil accessing api gateway

    • @orilsoftware
      @orilsoftware  Місяць тому +1

      Hi! Dealing with CORS (Cross-Origin Resource Sharing) errors from the frontend while accessing an API gateway is a common issue.
      You can configure CORS in your Spring Cloud API Gateway to allow requests from specific origins. Spring Cloud Gateway provides built-in support for CORS configuration.
      @Configuration
      public class CorsConfig {
      @Bean
      public CorsWebFilter corsWebFilter() {
      CorsConfiguration corsConfig = new CorsConfiguration();
      corsConfig.addAllowedOrigin("*"); // Allow requests from all origins
      corsConfig.addAllowedMethod("*"); // Allow all HTTP methods
      corsConfig.addAllowedHeader("*"); // Allow all headers
      corsConfig.setAllowCredentials(true);
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", corsConfig);
      return new CorsWebFilter(source);
      }
      }
      By configuring CORS properly in your Spring Cloud API Gateway and backend services, you can ensure that your frontend application can successfully access APIs without encountering CORS errors.

    • @rashadbs2010
      @rashadbs2010 Місяць тому

      @@orilsoftware thanks

  • @collinstamaletalemwa6218
    @collinstamaletalemwa6218 5 місяців тому +1

    This is an insightful tutorial.
    Although, the security set up in the tutorial does not seem to protect the microservices themselves. If you access the endpoints in the user-service directly, responses will be successfully returned. If anyone has a solution to this, I would be glad if you shared!

    • @orilsoftware
      @orilsoftware  4 місяці тому +1

      Hi!
      If you've set up an API Gateway with security configurations to handle authentication and authorization but find that the microservices themselves are not adequately protected when accessed directly, here are a few steps you can take to enhance the security of your microservices:
      1. Secure Microservices Independently:
      Each microservice should have its own security configuration. If you're using Spring Security, ensure that each microservice project has appropriate security configurations in place. This includes specifying which endpoints are secure, setting up authentication mechanisms, and defining authorization rules.
      2. Use Common Security Configuration:
      Share a common security configuration across your microservices. Extract the security configuration into a separate module or library that can be included in each microservice project. This ensures consistency in security settings.
      3. JWT Token Propagation:
      If you're using JWTs for authentication in your API Gateway, ensure that these tokens are propagated to the microservices. The microservices should have mechanisms to validate and process incoming JWTs to authenticate and authorize requests.
      4. API Gateway as an Enforcer:
      Make the API Gateway the primary enforcer of security policies. Microservices should trust that requests coming from the API Gateway have already undergone necessary authentication and authorization. This may involve validating tokens, checking user roles, etc., within the microservices.
      5. Secure Endpoints with Annotations:
      In each microservice, use annotations like @PreAuthorize or @Secured (if using Spring Security) to secure specific endpoints. These annotations allow you to define method-level security constraints, ensuring that only authorized users can access certain functionalities.
      By implementing these measures, you can strengthen the security of your microservices, ensuring that they are protected even when accessed directly.

    • @collinstamaletalemwa6218
      @collinstamaletalemwa6218 4 місяці тому +1

      @@orilsoftware amazing stuff. I like that my perception was on the right track. Thanks for this!

    • @orilsoftware
      @orilsoftware  4 місяці тому +1

      @@collinstamaletalemwa6218 Great to know you find out tutorial useful :)

    • @mccayl5878
      @mccayl5878 2 місяці тому

      @@orilsoftware Thanks for the tutorial. Of course I have a couple questions for you.
      There are two approaches:
      1. Validate the token at the gateway.
      2. Validate the token directly in the service that the user invokes.
      Which approach is appropriate at what point? Is it possible to validate tokens using spring oauth2 resource server? Also, I noticed that spring oauth2 does not work well on version 3 of spring. I'm willing to say that spring oauth2 is shit.
      How can I pass the token through the gateway to the invoked microservice, and how do I pass it if a chain of microservices is involved in the invocation?

    • @orilsoftware
      @orilsoftware  2 місяці тому +1

      @@mccayl5878 Hi! Token Validation Approach:
      - Validating the token at the gateway is a common approach in microservices architectures. It provides a centralized point to enforce security policies and validate incoming requests.
      - However, there are scenarios where you might also want to validate the token in the individual microservices, especially if there are specific business rules or permissions associated with each microservice.
      - Typically, you would perform basic validation at the gateway (e.g., token format, expiration) and then perform more detailed validation, including checking scopes or permissions, in the microservice that the user invokes.
      You can validate tokens using Spring OAuth2 Resource Server. Spring Security provides extensive support for OAuth2, including acting as a resource server to validate access tokens.
      Spring Security's OAuth2 resource server can validate tokens issued by an authorization server and enforce security policies based on token attributes like scopes, authorities, etc
      The appropriate approach for token validation depends on your specific requirements, but a combination of gateway-level validation and microservice-level validation is common in microservices architectures. Spring Security and Spring OAuth2 provide robust capabilities for token validation and security enforcement, and staying updated with the latest versions is beneficial for compatibility and security reasons. Token passing between microservices can be achieved through HTTP headers, with the gateway playing a central role in managing the token propagation.

  • @user-xb2dv2ew6j
    @user-xb2dv2ew6j Місяць тому

    То есть, в случае обмена данными между микросервисами, это окей, что у нас дублирование кода? Просто люди пишут, что выносить общие DTO в отдельную библиотеку и подключать в разных микросервисах это не ок, это будет кошмар. И я не знаю, как поступать лучше.

    • @orilsoftware
      @orilsoftware  Місяць тому

      Hi! Duplicating code across microservices can indeed be a concern, especially when it comes to maintaining consistency and avoiding redundancy. Let's break down the options and considerations: Shared DTOs in a Separate Library and Duplicating DTOs in Each Microservice
      Both approaches have their pros and cons, and the choice depends on various factors including the size of your project, team structure, and development practices
      - Communication Overhead: Assess the overhead of coordinating changes to shared DTOs versus managing duplicated DTOs independently.
      - Versioning and Compatibility: Determine how changes to DTOs will be versioned and how backward compatibility will be maintained.
      - Team Collaboration: Consider the capabilities and preferences of your development team. Some teams may prefer the simplicity of duplicating DTOs, while others may prefer the consistency provided by shared libraries.
      - Project Complexity: Evaluate the complexity of your project and whether the benefits of code reuse outweigh the challenges of managing shared libraries.
      Ultimately, there is no one-size-fits-all solution, and the best approach may vary from project to project. It's essential to weigh the trade-offs and choose the option that best fits your project's requirements and constraints.

  • @emersontavera9362
    @emersontavera9362 4 місяці тому +1

    Very useful tutorial, thank u
    I have a question regarding the implementation of the bff pattern using a (react, angular...) app and spring cloud gateway + (keycloak or spring auth server). When I follow the authorization_code grant type hitting the gateway routes from the browser it redirects me to the auth server, i get authenticated and then the request goes back to the gateway which stores the tokens (in memory, redis, db, etc) then the request goes to the resource server with an auth token and I can get a response and a session id (no tokens in the browser).
    However, for some reason when I send a request from the react app to the gateway, the chain stops working and the auth server redirects me to its root /, instead of redirecting to the spring gateway, it would be really amazing if you could share some insights about the BFF pattern, there aren't many examples about this.

    • @orilsoftware
      @orilsoftware  4 місяці тому

      Hi! It sounds like you are encountering an issue with the redirection flow when implementing the BFF (Backend for Frontend) pattern with Spring Cloud Gateway and an authentication server (like Keycloak or a Spring Auth Server) using the authorization_code grant type. Here are some insights and considerations that might help you troubleshoot the problem:
      1. Cross-Origin Resource Sharing (CORS):
      Ensure that your Spring Cloud Gateway is configured to handle Cross-Origin Resource Sharing (CORS) appropriately. If your React app is making requests from a different origin, CORS headers must be set correctly to allow the browser to follow redirects.
      2. Redirect URIs Configuration:
      Check the configuration of redirect URIs in your authentication server (Keycloak or Spring Auth Server). Ensure that it allows redirection back to the Spring Cloud Gateway after successful authentication. The redirect URI in your authentication server configuration should match the URI of your Spring Cloud Gateway.
      3. Authentication Server Client Configuration:
      Verify that the client configuration in your authentication server matches the client (your React app) that initiates the authorization_code flow. Ensure that the client ID, client secret, and redirect URIs are correctly configured.
      4. React App Configuration:
      In your React app, ensure that the redirect URI specified during the authorization_code flow matches the URI configured in both the authentication server and the Spring Cloud Gateway.
      5. Token Storage and Propagation:
      Confirm that the authentication tokens obtained after the authorization_code flow are stored and propagated correctly from the Spring Cloud Gateway to the resource server. Ensure that the tokens are included in the headers of subsequent requests from the React app to the gateway.
      6. Testing Different Grant Types:
      Consider testing different grant types (e.g., password grant type for testing purposes) to isolate whether the issue is specific to the authorization_code flow or if it's a broader problem.
      By carefully examining these aspects, you may uncover the root cause of the redirection issue and ensure a smooth flow of authentication and authorization in your BFF pattern implementation.

  • @meoconhoccode
    @meoconhoccode Місяць тому

    can u tell me how to get user info in a service?

    • @orilsoftware
      @orilsoftware  Місяць тому

      Hi! To get user information in a service, you typically need some form of authentication and authorization mechanism in place. Once a user is authenticated, their information can be retrieved from the authentication context or a user session.
      If you're using JWT for authentication, user information may be embedded in the JWT token itself. You can decode the token to access the user details.
      - When the server receives a request with a JWT token, it verifies the token's signature to ensure its integrity and authenticity.
      - After verification, the server decodes the token to access the claims contained within the payload
      - Once the JWT token is decoded, the server can access the user information directly from the token's claims.
      - Common user information found in the claims includes the username, user ID, roles, and any additional custom attributes
      Overall, JWT provides a stateless and efficient method for authentication, allowing services to verify and extract user information directly from the token without the need for server-side session management.

  • @Natalie_Bil
    @Natalie_Bil 6 місяців тому

    Great tutorial!