DEV Community

Alexis MP for Google Cloud

Posted on Originally published at Medium on

AlloyDB Integration for Modern Java Apps — Connectivity and Auth

(this is part of a Java tour of Google Cloud Databases series)

AlloyDB for PostgreSQL is Google Cloud’s database for enterprise-grade workloads with full PostgreSQL compatibility and a cloud-native architecture. Connecting a Java application to AlloyDB is done through the AlloyDB Java Connector , a crucial component that goes beyond a standard JDBC driver.

The AlloyDB Java Connector’s Magic

The alloydb-jdbc-connector is a client library that functions as a smart socket factory for the standard PostgreSQL JDBC driver. It abstracts away the establishment of a secure database connection and takes care of :

  • mTLS 1.3 Encryption: automatic secure TLS 1.3 connection to the AlloyDB instance (no need to manage SSL/TLS certificates here).
  • IAM-Based Authorization: as a better alternative to (static) database passwords, the connector uses IAM for authentication and ADC (Application Default Credentials) to obtain a short-lived access token.
  • Dynamic IP Resolution: The connector communicates with the AlloyDB Admin API to fetch the current IP address (a Private IP, a Public IP, or a Private Service Connect) of the database instance, so you do not need to handle it explicitly, no hard-coding or environment variable needed. This makes events like failovers or maintenance easier to manage.

NOTE on using the Java Connector rather than the Auth Proxy: for JVM applications, the Java Connector runs in-process as a JDBC SocketFactory, eliminating the need to deploy and manage a separate sidecar container. The standalone Auth Proxy is best for non-JVM tools, legacy apps where you cannot modify the JDBC classpath, or environments with strict GraalVM native-image constraints.

But first, some groundwork

I’ll assume that you already have a project with an existing AlloyDB Cluster and primary Instance running in a specific region. If you don’t have that, check out the AlloyDB cluster creation guide or head directly to the console’s getting started section. You’ll need the admin password, the roles/alloydb.admin role, some tables in the public schema (use DVD Rental if you don’t have anything), and of course be able to reach the AlloyDB instance from your local machine (or from Cloud Shell).

I also strongly recommend that you install these in your favorite agent tool as you progress through the code and instructions of this series :

If you like learning from codelabs, try: Connect your application to AlloyDB data and deploy on Cloud Run.

Let’s start with creating a Service Account, the identity your Java application will use:

gcloud iam service-accounts create java-alloydb-connector \
    --display-name="Java Application DB Connector"
# locally you'll need to impersonate this account or use your own IAM user
# on Cloud Run/GCE/GKE, attach this SA to the compute service/workload
Enter fullscreen mode Exit fullscreen mode

Then grant it the required IAM roles: both roles/alloydb.client (needed to request an ephemeral mTLS certificate and connect to the instance) and roles/serviceusage.serviceUsageConsumer (required for IAM database authentication):

gcloud projects add-iam-policy-binding <PROJECT_ID> \
    --member="serviceAccount:java-alloydb-connector@<PROJECT_ID>.iam.gserviceaccount.com" \
    --role="roles/alloydb.client"

gcloud projects add-iam-policy-binding <PROJECT_ID> \
    --member="serviceAccount:java-alloydb-connector@<PROJECT_ID>.iam.gserviceaccount.com" \
    --role="roles/serviceusage.serviceUsageConsumer"
Enter fullscreen mode Exit fullscreen mode

Now enable IAM authentication on the instance to tell your AlloyDB instance to accept IAM tokens, not just passwords (this takes effect immediately, no instance restart required):

gcloud alloydb instances update <INSTANCE_ID> \
    --cluster=<CLUSTER_ID> \
    --region=<REGION> \
    --database-flags=alloydb.iam_authentication=on
Enter fullscreen mode Exit fullscreen mode

Finally, register the IAM principal inside AlloyDB and grant it PostgreSQL table permissions. Notice how the .gserviceaccount.com suffix must be stripped for Service Accounts!

You can register the IAM user directly with gcloud (this automatically grants the internal alloydbiamuser role):

gcloud alloydb users create "java-alloydb-connector@<PROJECT_ID>.iam" \
    --cluster=<CLUSTER_ID> \
    --region=<REGION> \
    --type=IAM_BASED
Enter fullscreen mode Exit fullscreen mode

Then log in to your database as an admin (e.g., postgres) and grant schema and table privileges (IAM users must be created via gcloud, Terraform, or the Console because AlloyDB blocks granting the internal alloydbiamuser role directly in SQL):

-- Connect to your target database first
\c my_database

-- Grant permissions (IAM users are created with NO privileges by default)
GRANT CONNECT ON DATABASE "my_database" TO "java-alloydb-connector@<PROJECT_ID>.iam";
GRANT USAGE ON SCHEMA public TO "java-alloydb-connector@<PROJECT_ID>.iam";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "java-alloydb-connector@<PROJECT_ID>.iam";
Enter fullscreen mode Exit fullscreen mode

Make sure to use double quotes in SQL as they’re required because of the @ and dots.

How-To: Connecting to AlloyDB with a JDBC or Spring Boot app

Configuring HikariCP to work with the AlloyDB Java Connector requires specifying key properties that instruct the standard PostgreSQL driver to delegate socket creation to the connector. This requires Java 11 or higher (but I hope you’re using Java 17, 21 LTS, or higher!).

“Plain” JDBC

First, dependencies (pom.xml):

<dependencies>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.7.14</version>
    </dependency>

    <dependency>
        <groupId>com.google.cloud.alloydb</groupId>
        <artifactId>alloydb-jdbc-connector</artifactId>
        <version>1.4.0</version>
    </dependency>

    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
        <version>7.1.0</version>
    </dependency>
</dependencies>
Enter fullscreen mode Exit fullscreen mode

Here’s a complete sample that configures HikariCP with the AlloyDB SocketFactory and queries the film table from the DVD Rental schema to verify both IAM authentication and table privileges:

Notice that the JDBC URL jdbc:postgresql:///%s contains no host information. This is a key indicator that the SocketFactory is in control, as it is responsible for finding and connecting to the correct instance IP address.

For connectivity troubleshooting, check out the bottom of this post and make sure to read the AlloyDB Connection Overview.

Using Spring Boot

Spring Boot simplifies database connectivity by automatically configuring a HikariCP connection pool based on your properties, allowing you to integrate the AlloyDB Connector with almost no manual coding.

You only need to add the AlloyDB Connector to your existing Spring Boot project. Spring Boot’s spring-boot-starter-data-jpa or spring-boot-starter-jdbc already includes HikariCP (just ensure org.postgresql:postgresql is on the classpath):

<dependency>
    <groupId>com.google.cloud.alloydb</groupId>
    <artifactId>alloydb-jdbc-connector</artifactId>
    <version>1.4.0</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Using application.properties is the standard way to define your connection string within your project:

# No host or port is needed; the SocketFactory handles it.
spring.datasource.url=jdbc:postgresql:///my_database?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>&alloydbEnableIAMAuth=true
spring.datasource.username=java-alloydb-connector@<PROJECT_ID>.iam
# No password required when alloydbEnableIAMAuth is true
Enter fullscreen mode Exit fullscreen mode

Tips

If this long JDBC URL isn’t your thing, you can use the com.google.cloud:spring-cloud-gcp-starter-alloydb dependency, which lets you configure spring.cloud.gcp.alloydb.database-name, spring.cloud.gcp.alloydb.instance-connection-uri, and spring.cloud.gcp.alloydb.iam-auth-enabled=true.

If you want to keep your code clean of specific project IDs or instance names, you can leave your application.properties empty and set these environment variables in your deployment environment:

SPRING\_DATASOURCE\_URL=jdbc:postgresql:///my\_database?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/my-project/locations/us-central1/clusters/my-cluster/instances/my-instance&alloydbEnableIAMAuth=true

SPRING\_DATASOURCE\_USERNAME=java-alloydb-connector@my-project.iam

(If your organization still requires static database passwords instead of IAM authentication, do not hard-code them. Instead use Google Cloud Secret Manager to inject those dynamically using Spring Cloud GCP’s spring.config.import=sm:// and spring.datasource.password=${sm://alloydb-password}).

Passwordless Auth in Action

When Spring Boot starts, it detects the jdbc:postgresql prefix in the URL and initializes the PostgreSQL driver. Because the URL contains the socketFactory parameter, the driver delegates the actual network connection to the AlloyDB Connector. The connector then uses Application Default Credentials (ADC) to authenticate. This means that if your app is running on Cloud Run with the correct Service Account attached, the connection happens automatically and securely without any passwords in your config files.

This short app will help you test the connectivity to the database:

Here’s how to run it:

export SPRING_DATASOURCE_URL="jdbc:postgresql:///my_database?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>&alloydbEnableIAMAuth=true"
export SPRING_DATASOURCE_USERNAME="java-alloydb-connector@<PROJECT_ID>.iam"

mvn spring-boot:run
Enter fullscreen mode Exit fullscreen mode

Using Micronaut or Quarkus?

Whether you choose Micronaut or Quarkus , the underlying principles for connecting to AlloyDB remain the same.

Because the AlloyDB Java Connector operates at the JDBC driver level , the framework simply acts as a wrapper for the connection pool. You still include the same alloydb-jdbc-connector dependency, and the “magic” continues to happen through the SocketFactory and alloydbInstanceName properties:

Quarkus (application.properties** using Quarkus’s Agroal pool):**

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=java-alloydb-connector@<PROJECT_ID>.iam
quarkus.datasource.jdbc.url=jdbc:postgresql:///my_database
quarkus.datasource.jdbc.additional-jdbc-properties.socketFactory=com.google.cloud.alloydb.SocketFactory
quarkus.datasource.jdbc.additional-jdbc-properties.alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>
quarkus.datasource.jdbc.additional-jdbc-properties.alloydbEnableIAMAuth=true
Enter fullscreen mode Exit fullscreen mode

Micronaut (application.yml** using HikariCP):**

datasources:
  default:
    url: jdbc:postgresql:///my_database?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>&alloydbEnableIAMAuth=true
    username: java-alloydb-connector@<PROJECT_ID>.iam
    driver-class-name: org.postgresql.Driver
Enter fullscreen mode Exit fullscreen mode

Just as with Spring, these frameworks delegate the mTLS encryption, dynamic IP resolution, and IAM-based authentication to the connector library. Moving between cloud-native frameworks doesn’t change how you secure your database traffic or manage identities: Application Default Credentials (ADC) is used to achieve a passwordless, secure connection to your AlloyDB instance.

A note on the AlloyDB Connector in GraalVM Native Mode

When compiling your application into a GraalVM Native Image (whether with Spring Boot, Micronaut, or Quarkus), there is one specific challenge: Reflection and SSL.

The PostgreSQL JDBC driver instantiates com.google.cloud.alloydb.SocketFactory dynamically via reflection. To prevent GraalVM’s static analysis from stripping the class during native compilation, register it for reflection:

Spring Boot 3+: Add @RegisterReflectionForBinding(com.google.cloud.alloydb.SocketFactory.class) to your main application or @Configuration class.

Quarkus: Add @RegisterForReflection(targets = com.google.cloud.alloydb.SocketFactory.class) to a CDI bean or configuration class.

Troubleshooting

A common point of confusion and failure is the format of the username. The format differs for user accounts, groups, and service accounts:

  • IAM User Account (or IAM Group): Use the full email address (e.g., db-user@example.com or all-devs-group@example.com).
  • Service Account: Use the email address, but strip the .gserviceaccount.com suffix (e.g., for my-sa@my-project.iam.gserviceaccount.com, the database username is my-sa@my-project.iam).

If you get a FATAL: password authentication failed for user or AlloyDB IAM authentication failed error, check these common pitfalls:

The Suffix:

Did you accidentally include .gserviceaccount.com in the database username or CREATE USER command? (remove it).

The alloydbiamuser Role:

Did you create the user via gcloud alloydb users create — type=IAM\_BASED (or Console/Terraform)? Creating a user with raw SQL CREATE USER will not work for IAM authentication because AlloyDB restricts GRANT alloydbiamuser to the control plane.

The Environment & Local Impersonation:

Is the environment where the Java code is running actually authenticated as the target principal

=> Cloud Run: Ensure the Service Account is attached to the Cloud Run service definition and has both roles/alloydb.client and roles/serviceusage.serviceUsageConsumer.

=> Locally (connecting as a Service Account): Impersonate the Service Account so ADC mints tokens for that SA instead of your personal email:

gcloud auth application-default login \
    --impersonate-service-account=java-alloydb-connector@<PROJECT_ID>.iam.gserviceaccount.com
Enter fullscreen mode Exit fullscreen mode

The Delay:

IAM policy changes can take 60–120 seconds to propagate. If you just created the Service Account or role binding, wait a minute and retry.


Top comments (0)