Unlocking Google Calendar API with Keycloak: A Developer's Guide
Tags: keycloak, googleapi, tokenexchange, spring
Published: 2023-05-20 07:52:14

# 1. Overview
Unlock the power of Keycloak for seamless authentication and authorization in your applications. This comprehensive guide is designed for software developers who want to integrate Keycloak into their systems to enable secure user login and token exchange with Google. 

By following step-by-step instructions and best practices, you'll learn how to leverage Keycloak's robust features to facilitate seamless authentication and obtain a Google token. With this token, you can effortlessly access the Google Calendar API and unlock a wealth of functionality for your application. Enhance user experience and streamline calendar integration - start implementing Keycloak and Google integration today.

You need prior knowledge with:

- Google
- Keycloak
- Spring Boot

# 2. Google
Before we can do the integration with Keycloak we need to create a project in Google Console, create a credential and obtain OAuth client id and secret.

If you haven't done so, you can create a Google console account at  https://cloud.google.com/cloud-console.

## 2.1 Creating the Google Cloud Project
At the top left of your Google Cloud Console, click the project and click New Project.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6f7pwciuh7wp4n5t38jt.png)

I call this project "Lab".
## 2.2 Create OAuth2 Client
The next step is to create the OAuth2 client credential that will give us the client id and secret. This combination will be used when we set up the Google Identity provider in Keycloak.

With the Lab project selected, find API & Services / Credentials in the menu.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/00auccu017eizp2gmmyr.png)

Click Create Credentials with the following inputs:

Type: OAuth client ID
Application type: Web application
Name: Lab

There are two important entries in this section:

Authorized Javascript origins

This should be the URL where the request for login will come from.

Authorized redirect URIs

This entry is a common cause of problems if not properly set up. This is where Google will redirect the user after a successful login.

Some common redirect URIs.

Amazon Cognito: https://lab.auth.ap-southeast-1.amazoncognito.com/oauth2/idpresponse
Postman: https://www.getpostman.com/oauth2/callback
Keycloak broker: http://localhost:8080/realms/czetsuyatech/broker/google/endpoint
Keycloak token: http://localhost:8080/realms/czetsuyatech/protocol/openid-connect/token

When you have a redirect issue, this is one of the first things you may want to check.

This is how my Lab client looks like.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gdbhmhk1u8gw5631b383.png)

On the same page, you should be able to see the client id and secret. Take note because we will need them later.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hx392nxc34knlq2h98hd.png)

## 2.3 Setup OAuth Consent Screen
This section will ask for several application-related settings. You can enter values as you see fit, but normally I set the following.

Non-sensitive scopes:

- auth-userinfo-email
- auth-userinfo-profile
- openid
Don't forget to add a test user. We will use it to login later.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/61xi2r6zkimt7tx2hnwp.png)

# 3. Keycloak
For this exercise, we need to create a new Keycloak realm and client. We must enable authentication in the client.

## 3.1 Client

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hqne0pzftaxnv2ioxsr.png)

Enabling authentication will give us access to Keycloak's client and secret, which we will need later for testing. Take note of it.

We also need to download the Adapter config of our newly created client.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dlo3u7i4tgunx9zur6cs.png)

The downloaded config should look like this. Save it as we will use it in our Spring Boot application later.

```
{
  "realm": "czetsuyatech",
  "auth-server-url": "http://localhost:8080/",
  "ssl-required": "external",
  "resource": "web-front",
  "credentials": {
    "secret": "BxYWD11qCAW6ZybPTy6b9M8ej0thTxxx"
  },
  "confidential-port": 0
}
```

## 3.2 Identity Provider
Identity providers are third-party services that allow users to log in to Keycloak. In our example, we will do an authorization as well by exchanging the Keycloak token to Google to allow us to call Google API services such as Calendar and Gmail.

So login to Keycloak as admin, click Identity Providers on the left side, Click Add Provider, and select Google.

In the Client ID and secret fields, enter the values that we saved when we were configuring the Google client earlier.

Under Advance settings, change the value of Scopes to "_email profile openid https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.events https://www.googleapis.com/auth/gmail.readonly_", without double quotes. This will give us permission to call list endpoints from Calendar and Gmail APIs.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r79unbkhq7322ou8tx11.png)

## 3.3 Permissions
In this section, we will give our client permission to exchange tokens with the newly created Google identity provider.

On the identity provider page, click the Permissions tab. Toggle Permissions enabled to ON. Under the Permission list, click token-exchange.

Set the Decision strategy to Unanimous. Click Save.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypp6qqvktgxmvcoraj7d.png)

Next, we need to create the permission scope. At the top-left of the page, click Client details. It should redirect you to the Authorization tab. Open the Policies sub-tab. Create a new policy with the following values:

Type: Client
Name: google-token-exchange
Clients: web-front (the Keycloak client we created earlier)
Logic: Positive

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ocn5te2c92kzfszr1ut.png)

Go back to your Google identity provider’s permission page and set the Policies to the one we just created.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lf69pcrjffxo8prgiwfa.png)

The setup should now be ready to exchange tokens.

# 4. Testing
To test the exchange of tokens between Keycloak and Google, I have created a Postman collection where we can:

- Authenticate a user
- Exchange Keycloak to Google token

Before we proceed with the testing, we need to run a Keycloak instance. I have prepared a docker-compose to do that.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txti4bl4amtfthj44pwc.png)

We need to authenticate our user, so create a new POST request in Postman and use OAuth2 authorization. Set the URL to http://localhost:8080/realms/czetsuyatech/protocol/openid-connect/token.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7w6egwndvph1aiingsh.png)

Be sure to set the client id and secret to the ones we saved earlier when we created the Keycloak client.

For the truncated values:

Callback URL: https://www.getpostman.com/oauth2/callback

Auth URL: http://localhost:8080/realms/czetsuyatech/protocol/openid-connect/auth

Access Token URL: http://localhost:8080/realms/czetsuyatech/protocol/openid-connect/token

Click Get New Access Token. It should redirect us to a Google login page, use the test email address that you added earlier when creating the Google client.

The next page will show you the scopes that will be permitted for your user. We defined this when we created the Google identity provider earlier.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6x4q39v0evkx1xniduf.png)

Click Allow.

Copy the access token and paste it on a bearerToken variable. The succeeding requests will have Authorization Type = Bearer and will use this value.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ce5fkzuuyjxdw9jlks8q.png)

The Body of the request must have the following URL encoded parameters:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11pv1gu93k9p5opk1yvj.png)

Click Send. It should return with the following response.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6lsentnlwlf38yea2df6.png)

This is the token that we can use to access Google APIs.

Obviously, we need to automate the process if we wanted this feature in our application. Thus, I have created a Spring project to do it.

# 5. Spring Project
This project demonstrates the token-exchange feature available on Keycloak. With this, we can exchange Keycloak for Google’s token, which we can use to call Google APIs.

_Note: This project is only available for my sponsors https://github.com/sponsors/czetsuya._

## 5.1 Available Features

- Get the bearer token from the request and store it in a Bean that can be autowired.
- Exchange Keycloak token to Google, this will allow us to call Google APIs (Calendar, Gmail).
- Use Spring exchange to provide abstraction in calling Google APIs.
- Endpoints to list Calendar events and Gmail messages.

The heart of the application exchanges tokens between Keycloak and Google.

```
@Component
public class GoogleTokenExchange implements TokenExchange {
 
  @Override
  public String exchangeToken(String accessToken) {
 
    AuthzClient authzClient = AuthzClient.create();
    Configuration keycloakConfig = authzClient.getConfiguration();
    String baseUrl = authzClient.getServerConfiguration().getTokenEndpoint();
 
    RestTemplate restTemplate = new RestTemplate();
 
    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED.toString());
    headers.add("Accept", MediaType.APPLICATION_JSON.toString());
 
    MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
    requestBody.add("client_id", keycloakConfig.getResource());
    requestBody.add("client_secret", keycloakConfig.getCredentials().get("secret").toString());
    requestBody.add("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange");
    requestBody.add("subject_token_type", "urn:ietf:params:oauth:token-type:access_token");
    requestBody.add("subject_token", accessToken);
    requestBody.add("requested_issuer", "google");
 
    HttpEntity formEntity = new HttpEntity<>(requestBody, headers);
 
    ResponseEntity<AccessTokenResponse> response = restTemplate.exchange(baseUrl, HttpMethod.POST, formEntity,
        AccessTokenResponse.class);
 
    return response.getBody().getToken();
  }
}
```

## 5.2 Testing
If you have subscribed as my sponsor, you will be given access to my repository and proceed with this testing.

The project provides two endpoints, to test calling list calendar events and Gmail messages from Google. Matching Postman requests are also available to make testing easier.

As we have done earlier, we need to get an access token from Keycloak and set it as bearerToken environment variable inside Postman.

Get Calendar Events Response

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ihegcw8glo30slgohqr1.png)

Get Gmail Messages

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zk1skgdifekuyt62ybri.png)

# 6. Source Code
All the resources used in this article and demo are available on the GitHub repository https://github.com/czetsuyatech/auth-exchange.

- Spring project source code
- Docker/compose file
- Keycloak realm
- Postman collection for testing

# 7. References

- https://www.keycloak.org/docs/latest/securing_apps/#_token-exchange
- https://www.keycloak.org/docs/latest/server_development/index.html#retrieving-external-idp-tokens
- https://developers.google.com/calendar
- https://developers.google.com/gmail/api/guides