📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Secure Your Microservices Using Keycloak | Spring Cloud Gateway | JWT | JavaTechie

Java Techie24:53

Transcription

Hi everyone, welcome to Java Tiki. Being a developer, we all know that security is a major cross-cutting concern for any application architecture, and it's really a very tough job to manage this security mechanism by ourselves, isn't it?

So, in this tutorial, I will explain how you can leverage Keycloak to secure your microservice application using API Gateway. Okay, all right. So, if you can remember, I already explained how to implement security in microservice architecture using JWT, right? If you don't remember, no worries, let's have a quick recap of how we designed security in our microservice application.

Okay, so in a typical microservice architecture, we do have these basic components or modules. If you observe here, we have two microservices like Sugi microservice and restaurant microservice, and then we have Eureka service registry, and then we have API Gateway for routing all the incoming requests. Let's assume the user wants to access Sugi, then a request will come to the API Gateway, and then API Gateway needs to authenticate that request. So, for that, we have created our custom auth service or identity service where we do manage our security-related stuff, right? So, API Gateway will send one JWT token to the authentication service or identity service. Then the authentication service will extract the user details from that token and then validate against the DB to perform the authentication. If it is successful, then route that request; otherwise, simply terminate it. So, the same flow will be applicable for the restaurant service as well. This is what we understood as security implementation in our previous architecture.

But did you observe here? In the authentication service or identity service, we are still dealing with security-related implementation. There is nothing wrong; we can do that. But here, I want someone who can manage security-related stuff on behalf of me. All the requests coming to my application, I want to delegate to someone to authenticate on behalf of me. That's why this Keycloak came into the picture. Not only Keycloak, like this, there are so many external identity providers available in the market like Okta, Azure AD, AWS Cognito, and many more.

Okay, so if you don't know what Keycloak is and its basic configuration, then I would strongly suggest you to check out my "Spring Security with Keycloak" video. I will also share the link in the video description for your reference. Okay, I was talking about this particular video. And also, if you are not aware about how to implement security in microservice architecture using JWT, you can refer the start video. Okay, both the links I will share in the video description for your reference.

So, let me give some basic heads-up about what Keycloak is. Okay, basically, Keycloak is an open-source identity and access management tool, or you can simply say it as an IAM tool, who will manage the whole security mechanism of your application. So, in this design, rather than we manage the security mechanism and resource details in our code, we can delegate all the incoming requests from API Gateway to this Keycloak and we can ask him, "Hey Keycloak, can you authenticate this particular request using the JWT token?" If authentication succeeds, then only route that request; otherwise, simply terminate it. Okay, how simple is this, isn't it?

Let's step by step to implement this architecture in our existing microservice application. Okay, so without any further delay, let's get started.

[Music]

So, if you remember, this is what the exact microservice architecture we have designed before. To implement the security, we have two microservices, Sugi app and restaurant service. We have service registry, and we have API Gateway. Now, if I will go to the Eureka dashboard and if I will hit here, let's say 8761, right? In the Eureka dashboard, I can see all the three microservices being registered here.

Okay, now to begin with Keycloak, the first step you need to do: go to Keycloak. Either you can download the binary distribution on your machine. If not, just click on "Get Started." Then there are multiple ways you can use. You can download the Keycloak server, or else we will go with Docker. Okay, rather than installing it on our machine, we'll use the Docker command to start a Keycloak server for us. So, go here, and this is what the Docker command to start a Keycloak server. Before that, make sure you should start your Docker in your machine. Then, once your Docker engine will start, then you can copy this particular command, then you can add this command here. I just want to change the port because already my API Gateway is running on port 8080. Okay, so I want to run this particular Keycloak server on 9090, and I am starting in the dev environment, and this is what the version, the latest version I am using. Okay, so just copy this command, open the terminal, and simply trigger this. It will take a few seconds to start. Meanwhile, just remember we have defined the username as `admin` and password as `admin`. This will be our initial login credential. Okay, so you can change whatever you want.

So, it's still loading. It will take a few seconds. If you do it the first time, it will first pull the Docker image of the Keycloak server, then it will start the server. Since I already pulled the image, so it's just starting the server for me. So, I believe it started. Let's verify that. Go to the browser and then hit the endpoint `http://localhost:9090`. Just enter it. Yeah, so you can see this is the dashboard. Now you need to click on this "Administration Console." Loading the admin UI. Here you need to give the credential `admin` and `admin`. That is what our initial login credential. So, just provide `admin`. Now click on "Sign In." This is what the dashboard of the Keycloak server.

Okay, now the first step to integrate this Keycloak to your application: first, you need to create a realm. Okay, so a realm manages a set of users, credentials, roles, and groups. The users you create in this particular realm belong to that particular realm itself. Okay, so when they log in to Keycloak, they log in into a specific realm. By default, you can see the realm name is `master`. So, you need to create a new realm for your application. Okay, just click on this, and then you just need to give the name here. So, I am giving `spring-boot-microservice-realm`. Nothing else you don't need to do anything. Just click on "Create." Make sure you just copy this name, I mean, for your future reference. Then click on "Simply Create." So, the realm name is created. You can see here in the dropdown, we can able to see our own realm.

Now, the next step: we need to configure the client. Okay, so a client in Keycloak is a resource server, that is, the server that hosts the resource that needs to be secured. In our case, it will be our API Gateway, which we already created. But we need to do the client configuration, and the same configuration we need to provide in our API Gateway so that all the requests coming to our API Gateway will connect to this particular client and realm.

So, just click on "Clients." Now you have the option to create a new client. Just click on this, and you can give the name. Let's say I am giving `microservice-auth`. This is what my client name. I want to give the name same. Description also same. Let me have a copy of it. Then simply click on "Next." And here, we need the client authentication. Right? Just enable it. And the authentication flow we need that is "Service Account Role." Just disable others. Okay, now click on "Next." We don't need authorization at this moment, so I just disable it. Now click on "Next." Root URL. Root URL of our application is `http://localhost:8080`. Okay, so if you observe in the API Gateway, the port we have not defined any port, right? So, it will be running on port 8080, which is the default one. So, let's configure the same. Home URL also same. Fine. Click on "Save."

Now, once you saved it, immediately you need to get the secret. Client secret. Just click on "Credentials," and here you can find the client secret. Just copy that for your reference. All good. So, let's review the settings again. Client ID and name we have given. "Always display in UI." I don't know about this particular field, so let it be disabled. And this is where the URL we have configured, and we need client authentication of type "Service Account Roles." Basically, you are doing the client credential-based authentication. I am not going to add the user and doing the authentication because that already I covered as part of this particular video. Okay, same you can do the copy-paste in your API Gateway to play with the user-related credential or password credential. Okay, fine. Now, anything else? No, looks good. Click on "Save." That's it. Okay, all the required information we already configured.

Now, if you check the endpoint configuration, just click on the "Realm Settings." "OpenID Endpoint Configuration." Because if you observe here in the client, go to the client, we are using OpenID Connect. Okay, that is what the authentication mechanism we are using. You will find the two options, OpenID and SAML, but we are using the OpenID Connect. So, if you go to the "Realm Settings" and if you will click on this particular configuration, you can see all the endpoints. So, in our case, the issuer URL endpoint is nothing but our realm endpoint. So, we need this particular endpoint. Just copy it. Next, if we'll go and check, there is something called "Token Endpoint." All the requests will come to this particular endpoint to authenticate your token. Okay, so let me copy this particular endpoint again. I mean, this we need to pass from our Postman. Okay, let me copy this. Fine. These are the information we need. And if you read it carefully, there are so many inputs you can find. Okay, JWKS URI, and what is the grant type support? Authorization Code, Implicit, Refresh Token, Password. In our case, we are using this "Client Credentials." Okay, let me zoom this for you. Different types of grants are available here, but we are going to use this "Client Credentials." Okay, that's it. There are so many things. We are not going to discuss each and every key and value from the JSON. That's fine. Let me clear this.

Now, the next step: you need to... we are done with the Keycloak setup. Okay, all the client configuration and realm we have created. Now, same, we need to integrate to our API Gateway so that all the requests coming to API Gateway will simply redirect to this particular realm. So, for that, what you can do, go to your API Gateway. First of all, I need to remove all the dependency of JWT. Because you already implemented JWT-based security in this API Gateway, so let me remove that first. So, first, let me remove this dependency. Then, let me remove this class. We don't need this filter. Remove it. Put it there in `utility/util`. Just remove it. Okay, and in the `application.yml`, I will not delegate requests to this particular authentication filter, which is not existing at this moment. Remove it. Now, here, rather than sending it to our authentication mechanism, we want to send it to the Keycloak server, right? So, for that, what you can do, the simple step: you need to configure the issuer URI here so that all the requests will go to the particular realm. So, for that, what you can do, let's write it here: `security.oauth2.resourceserver.jwt.issuer-uri`. And we want to implement the security like JWT. And what is the issuer URI? This one. That is what we have copied here, right? So, just copy this. We want to delegate all the requests to this particular realm. This configuration is required.

Let me refresh this. And also, make sure you need to add the dependency in your `pom.xml`, which is `oauth2-resource-server` and `security`. Okay, if you observe our API Gateway, we designed using the WebFlux, which is reactive programming. Okay, so let me add those dependencies: `oauth2-resource-server` and `spring-boot-starter-security`. Just update it. And if you observe in each and every microservice, what we have defined here, we are using the latest Spring Boot version, which is 3.1.2. All good. Fine.

Now, to delegate all the requests coming to this API Gateway to Keycloak server, we need to provide a configuration. And also, I don't want to apply the security while accessing this particular endpoint, which is `/eureka`. So, we need to configure this information in our API Gateway to bypass `/eureka` related endpoint and delegate all the requests to the Keycloak server. So, for that, what you can do, we need to create a class here. So, just create a package and then I'll create a class `SecurityConfig`. Now, simply annotate these are the `Configuration` and just enable the `EnableWebSecurity`. That's it.

Now, the step is very simple. We need to create a `SecurityFilterChain`. So, I'll create a `Bean` of it: `securityWebFilterChain`. Then pass the argument `ServerHttpSecurity`. Now, next, first I need to disable the CSRF. So, `ServerHttpSecurity.csrf()`. What I can do, I'll just use lambda here. Okay, so we can change it to the method reference. Fine. Then just use `authorizeExchange()` and tell them if URL is coming with `/eureka/*` just permit all the requests. So, what you can do, again, you need to play with the lambda. `exchange.pathMatchers()` and you can define the pattern here. What is the pattern? `/eureka/**`. Okay, so simple. I need to tell here if the request is coming with `/eureka/**` then permit all the requests. Otherwise, for any other `exchange`, just authenticate them. Fine. Very simple.

Now, the next step: I need to tell that `oauth2-resource-server`. Okay, based on the JWT. So, specify `oauth2ResourceServer()` again. Here also, you need to play with the lambda. I mean, the Spring Boot version 3.1 has the syntax change in `securityConfig`. You need to play with the lambda functional programming. Otherwise, it will just give you the error. This particular method is deprecated. That's fine. Now, here, what I can do, I will say `jwt()`. Okay, and with the `defaultJwtCustomizer`. `defaultJwtCustomizer`. That's it. Once everything is done, I just want to build it. Fine. The steps are very simple, guys. What we have done here: we have disabled the CSRF, and we told the security that if the URL is coming with this, then permit all the requests, and for any other request, just authenticate them. And here, the resource server, I am using `oauth2-resource-server` with JWT. Okay, and then at the end, I just build this particular object and I return it back. Fine. Now, I just need to annotate here `@Bean`. That's it.

So, we can start the application to verify the behavior. Before that, first, let me see. Okay, so Sugi and restaurant service are up and running. Let me only restart this Gateway. Okay, because you have did the code change in this API Gateway. So, what I'll do, I'll just restart it. Meanwhile, let's go to Postman and verify the endpoint. So, this particular endpoint from the API Gateway, `8080`, will hit the Sugi endpoint, and `8080`. Okay, this one, right? Yeah, `8080` restaurant will hit the restaurant microservice. Let's see if it is coming up. So, API Gateway is up and running. Just verifying the dashboard. Eureka, you can see here, API Gateway is up and running.

Now, first, let me hit the endpoint of this particular Sugi. Okay, so I will just create a new Sugi. If I'll send the request, what I am getting here? The status code is `401`. It means I am not an authenticated user to access this particular endpoint. How we can authenticate, or who will authenticate for us? Keycloak server. How? Using the JWT. Okay, so we need to first generate a token by giving all the information what we have copied here. What is the client name? Client secret? And endpoint? We need to get the token, then we can use the same token to access all the endpoints. Okay, this is a very simple step.

So, what you can do, go to the authorization, choose the authorization type as `OAuth 2.0`. Now, is there any available token? Yes, there are three tokens which I already created before. Just ignore it. I will show you how you can create a new token. Okay, so give the token name `app-token`. See here, there are different grant types which we saw in the OpenID configuration: `client_credentials`, `password_credentials`, `authorization_code`, `implicit`, `authorization_code` with PKCE. There are different types of grant types. The one which you will try now: `client_credentials`. Now, what is the access token URL? The access token URL is the same which we already copied. Okay, just copy it properly. Just add it. And what is the client ID? The client ID you have defined: `microservice-auth`. Okay, same name you need to give here. And what is the client secret? We already copy the client secret. Just copy this. Go here, paste it. Okay, and scope, you can skip it. There is no sense to specify anything. And client authentication is the basic authentication header. Send as basic authentication header. Send client credentials in body. Okay, so we will just choose the default one. All good. These are the key information you need to provide. Okay, what is the grant type you want to use? What is your token URL? What is the client ID and client secret? That's it. Now, you need to get a new token. So, it will take three to four seconds to generate a token for you. This is the token I want to use. The same token. Just use token.

Now, if you observe here in the token section, "Current Token," the token which you created, `new-app-token`, is being assigned here. And this is the value, and this is the bearer. Okay, now send the request. We are getting the result. So, what happened? When you trigger the request, it passes the token which we generate. Now, it will take the token and will go to the Keycloak server. And if you observe here in Keycloak, we have "OpenID Configuration," right? Go here in this "OpenID Configuration." There is something called "Token Endpoint." Based on that, it will generate the token and it will validate that token. Okay, and the request will land to this particular realm. That is what we have created. And it will validate. If things are good, it will allow you to get the response. Otherwise, it will give the `401`.

Now, let's try out the restaurant service. This is the restaurant endpoint, right? From the API Gateway. Now, if I'll send the request, I am getting `401` because I have not given the token here. So, how I can give the token? The authorization type will be `OAuth 2.0`. Either generate a new token, or else you can use the existing token which you created, `new-app-token`. Send the request. We got the result. Fine.

So, point to note here: we are using the client credential. But if you want to use the username and password-based authentication, then you need to choose "Password Credentials" and you need to give the username and password. Since we don't create any user so far, you can go here. There is an option called "Users." You can create the user and you can validate against this particular grant type, which is "Password Credentials." So, already explained how you can play with the password credentials by creating the user and role in this particular video. "Secure Spring Boot Microservices with Keycloak using OpenID." Same, you need to do in your API Gateway to achieve this particular grant type.

So, I believe this particular security implementation flow is clear for you. Rather than authenticating the request, we are delegating that request to the Keycloak server. And Keycloak server is able to authenticate that particular token, and if it is valid, we are able to access our endpoint. Okay, so these are pretty simple steps what we have done in this video. Do let me know in the comment section if you guys have any doubts. That's all about this particular video, guys. Thanks for watching this video. Meet you soon with a new concept.