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.
Thanks for the clean and short tutorial. I am developing my project by following your instruction. I have one question here. If i want to get the get the authenticated username in /secured api, how will I get that ?
Hi! To retrieve the authenticated username in a `/secured` API endpoint, you'll first encode the username into the JWT token during its creation step. When the token is received in your API Gateway or downstream service, use a JWT library to parse it and extract the username from the token's claims (`getBody().getSubject()`). This ensures that the username, securely embedded in the JWT token during issuance, can be reliably accessed for authentication purposes in your application endpoints.
Could you please make complete series for one project microservice which cover, Eureka client Eureka Server Api gateway Circuit breakers Distributed tracing Centralized logging Jwt security Saga pattern Swaggaer api doc Spring Data Jpa concepts Etc.
Hi! We’re glad you found the topic interesting. We’ll consider your ideas for our next tutorials. In the meantime, feel free to check out our other tutorials! :)
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?
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.
Hi, can you explain to me how to dockerize a Spring Boot multi-module Maven project? I'm trying to do it but the API-gateway doesn't find the services and the services crash, they only run the databases in their containers. It would be good to see how you dockerize the one in this video.
Hi! To dockerize a Spring Boot multi-module Maven project, ensure each module/service has its own Dockerfile. Use a docker-compose.yml file to orchestrate them, with each service configured to connect to its database and exposed via the API gateway. In docker-compose.yml, list each service and database, setting service names as hostnames for internal communication. Configure routing in the gateway using the service names and ports, like service-one:8081. Finally, run docker-compose up-build to start everything. Check logs with docker-compose logs -f for troubleshooting. This setup ensures proper networking and service discovery!
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.
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?
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.
@@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.
@@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 :)
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.
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.
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.
The bearer token we are setting in authorisation header, for that we need to save token in browser cookie. But that is not safe because of xss. What to do for that?
Hi! Storing tokens in browser cookies does have security implications, especially with XSS. To make it safer, you can use the following approaches: HttpOnly and Secure Cookies: Store the JWT in cookies with the HttpOnly and Secure flags. This prevents JavaScript from accessing the token and ensures it’s only sent over HTTPS, reducing XSS risks. Also, set SameSite=Strict or Lax to prevent cross-site request leaks. Access Token and Refresh Token Strategy: Use a short-lived access token stored in a secure cookie, and manage refresh tokens securely on the server side. This limits the exposure of sensitive data and allows refreshing the token without exposing it to client-side scripts. Both methods improve security while keeping your API Gateway functional.
Hi! For this demonstration, we didn't use Spring Security because we wanted to illustrate how to handle JWT tokens directly. This approach shows the fundamental steps of encoding and decoding JWT tokens without the abstraction provided by Spring Security. However, in a production environment, it's highly recommended to use Spring Security for its robust security features and ease of integration.
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?
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 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.
@@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?
@@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.
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 ❤
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.
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.
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!
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.
@@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?
@@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.
То есть, в случае обмена данными между микросервисами, это окей, что у нас дублирование кода? Просто люди пишут, что выносить общие DTO в отдельную библиотеку и подключать в разных микросервисах это не ок, это будет кошмар. И я не знаю, как поступать лучше.
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.
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.
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.
Hi! To handle JWT authentication centrally, configure JWT verification in your API Gateway. This way, the Gateway will handle the JWT token validation for all incoming requests. Use Spring Security to set up this verification, allowing only authenticated requests through. Once verified, extract user details from the JWT token and add them to the request headers. Then, forward these enriched requests to downstream services. This avoids the need to repeat JWT validation in each service. In your downstream services, simply read the user details from the headers. This centralizes authentication logic in the Gateway, making your microservices architecture cleaner and easier to maintain.
This video is a tutorial that briefly explains the key parts, and it is very useful.
Thank you very much.
Thank you for your feedback :)
Kudos to Ihor for another fantastic tutorial
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?
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.
Thanks for the clean and short tutorial. I am developing my project by following your instruction. I have one question here. If i want to get the get the authenticated username in /secured api, how will I get that ?
Hi! To retrieve the authenticated username in a `/secured` API endpoint, you'll first encode the username into the JWT token during its creation step. When the token is received in your API Gateway or downstream service, use a JWT library to parse it and extract the username from the token's claims (`getBody().getSubject()`). This ensures that the username, securely embedded in the JWT token during issuance, can be reliably accessed for authentication purposes in your application endpoints.
very useful information. Thanks!
Hi! Great to know you find this tutorial useful :)
Could you please make complete series for one project microservice which cover,
Eureka client
Eureka Server
Api gateway
Circuit breakers
Distributed tracing
Centralized logging
Jwt security
Saga pattern
Swaggaer api doc
Spring Data Jpa concepts
Etc.
Hi! We’re glad you found the topic interesting. We’ll consider your ideas for our next tutorials. In the meantime, feel free to check out our other tutorials! :)
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?
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.
@@orilsoftware Pls. Can you share material for roles and scope authentication on Gateway?
Hi, can you explain to me how to dockerize a Spring Boot multi-module Maven project? I'm trying to do it but the API-gateway doesn't find the services and the services crash, they only run the databases in their containers. It would be good to see how you dockerize the one in this video.
Hi! To dockerize a Spring Boot multi-module Maven project, ensure each module/service has its own Dockerfile. Use a docker-compose.yml file to orchestrate them, with each service configured to connect to its database and exposed via the API gateway. In docker-compose.yml, list each service and database, setting service names as hostnames for internal communication. Configure routing in the gateway using the service names and ports, like service-one:8081. Finally, run docker-compose up-build to start everything. Check logs with docker-compose logs -f for troubleshooting. This setup ensures proper networking and service discovery!
@@orilsoftware thank you very much friend, it worked very well for me.
thank you so much, but can you tell me how to write open point for pattern like /product/{id} ?
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.
Thank you for awesome tutorial. it's really helpful
pls stop background music in future video🙂
Hi! Thank you for your feedback! Great to know you find this tutorial useful :)
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?
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.
@@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.
@@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 :)
thanks @oril .. i have one issue how to deal with cors error from frontend whil accessing api gateway
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.
@@orilsoftware thanks
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.
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.
Im so grateful for your help. Thks so much.
Музыка на фоне зачетная 😎
😉
The bearer token we are setting in authorisation header, for that we need to save token in browser cookie. But that is not safe because of xss. What to do for that?
Hi! Storing tokens in browser cookies does have security implications, especially with XSS. To make it safer, you can use the following approaches:
HttpOnly and Secure Cookies: Store the JWT in cookies with the HttpOnly and Secure flags. This prevents JavaScript from accessing the token and ensures it’s only sent over HTTPS, reducing XSS risks. Also, set SameSite=Strict or Lax to prevent cross-site request leaks.
Access Token and Refresh Token Strategy: Use a short-lived access token stored in a secure cookie, and manage refresh tokens securely on the server side. This limits the exposure of sensitive data and allows refreshing the token without exposing it to client-side scripts.
Both methods improve security while keeping your API Gateway functional.
Great tutorial!
Hello! We’re happy to know that you find our tutorial valuable :)
so you don't use spring starter security dependency or any security dependency at all?
Hi! For this demonstration, we didn't use Spring Security because we wanted to illustrate how to handle JWT tokens directly. This approach shows the fundamental steps of encoding and decoding JWT tokens without the abstraction provided by Spring Security. However, in a production environment, it's highly recommended to use Spring Security for its robust security features and ease of integration.
Great video, thanks! Do you have a GitHub link to this project?
Hello! Yes, you can find this project here on GitHub github.com/oril-software/spring-cloud-api-gateway-jwt 🙂
YOU SAVED ME
Great to know this tutorial is useful for you :)
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?
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.
@@orilsoftware If I use Spring Security at the API Gateway, is that a bad idea?
@@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.
@@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?
@@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.
🔥🔥🔥
We are delighted that you find this video interesting!
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 ❤
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.
excellent
Hello! Great to know that you find this tutorial useful :)
can u tell me how to get user info in a service?
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.
Дякую
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!
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.
@@orilsoftware amazing stuff. I like that my perception was on the right track. Thanks for this!
@@collinstamaletalemwa6218 Great to know you find out tutorial useful :)
@@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?
@@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.
То есть, в случае обмена данными между микросервисами, это окей, что у нас дублирование кода? Просто люди пишут, что выносить общие DTO в отдельную библиотеку и подключать в разных микросервисах это не ок, это будет кошмар. И я не знаю, как поступать лучше.
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.
saved, thanks 🤗
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.
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.
Hvala gdje cuo i ne cuo
how can I create a filter for each service? because I dont want to do all JWT service on each microservice
Hi! To handle JWT authentication centrally, configure JWT verification in your API Gateway. This way, the Gateway will handle the JWT token validation for all incoming requests. Use Spring Security to set up this verification, allowing only authenticated requests through.
Once verified, extract user details from the JWT token and add them to the request headers. Then, forward these enriched requests to downstream services.
This avoids the need to repeat JWT validation in each service.
In your downstream services, simply read the user details from the headers. This centralizes authentication logic in the Gateway, making your microservices architecture cleaner and easier to maintain.
Great tutorial!
☺