OAuth in Quarkus

OIDC with Google & Quarkus

How to configure Quarkus OIDC with Google Cloud credentials?

Prabodh Agarwal
ITNEXT
Published in
5 min readMar 29, 2024

--

Photo by Hermeus on Unsplash

This article is a massive segue from my research on the lakehouse architecture. But this is much needed for the GPT world. If you Google/GPT/Gemini how to setup Quarkus OIDC with Google Cloud, none of the tutorials can be copy-pasted, so I aim to fill in that gap with this article 😄.

I have been researching & learning how to setup Project Nessie for my Apache Iceberg lake house architecture. I have started exploring and published my first article regarding the same. Apache Iceberg practitioners know that the catalog is a critical component of the architecture (newbies please take note of the same 😉).

One important catalog in this category is Project Nessie 🌊 by Dremio. I have been exploring this catalog and one important detail that stood out is the fact that it is written in 🥁🥁🥁 Quarkus.

Quarkus is a pretty exciting framework. I am yet to find opportunities to work on a production grade Quarkus applications, so I decided to jump into the Nessie codebase to gain more exposure to the same.

I have done hello-world setup with Project Nessie as per their guide. Now, the next thing to understand is how to setup auth. We currently use Snowflake for a bunch of production use cases and have setup Google SSO for auth purpose. I want to setup a similar experience with Project Nessie as well. While scrolling around the auth setup doc, I noticed that we can use the native auth provided by Quarkus OIDC as well. So I decided to take a segue 🚲 and explore how to create a Hello World of OIDC in Quarkus 😃.

Now, I spent some time to setup a basic Quarkus application and taught myself basics of OAuth & OIDC thanks to Okta dev. I could perform a setup in Google Cloud and test it out on a OIDC debugger. Next, I wanted to setup the same in Quarkus as well.

There are a bunch of docs & tutorials from Quarkus & Okta that explain how to setup OIDC using Keycloak & Okta Auth, but these tutorials have a slight hiccup when it comes Google OAuth 😅. So I decided to redo the tutorial and publish a straightforward guide on the same.

I have setup the tutorial in this github repo. You can follow the link and stop reading this article! Otherwise, read on 😄.

Howto

  1. Setup

I am using gradle build system with Kotlin DSL to create a starter Quarkus project as follows.

mvn io.quarkus:quarkus-maven-plugin:create \
-DprojectGroupId=dev.pbd \
-DprojectId=quarkus-oidc-app \
-DnoCode \
-DbuildTool=gradle-kotlin-dsl \
-DprojectArtifactId=security-openid-connect-quickstart

This will create a directory called security-openid-connect-quickstart in
your $PWD.

2. Greeting resource

Create a Greeting resource in Quarkus as follows. There are well known examples on the internet as well as on ChatGPT & Gemini for the same.
Unfortunately, these examples suggest using javax.
Well, if you are on Java 11+ environment in 2024, you’ll know that javax has been long deprecated & the namespace has been moved to jakarta 🤷‍♂.

So add the jakarta dependency to the quarkus application as follows.

./gradlew addExtension --extensions='resteasy-jackson'

# or #

./gradlew addExtension --extensions='quarkus-rest'
package dev.pbd;

import io.quarkus.oidc.IdToken;
import org.eclipse.microprofile.jwt.JsonWebToken;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/")
public class GreetingResource {

@Inject
@IdToken
JsonWebToken idToken;

@GET
@Produces(MediaType.TEXT_HTML)
public String hello() {
return
"<html>\n" +
" <body>\n" +
" <h1>Hello " + idToken.getClaim("email") + "</h1>\n" +
" </body>\n"+
"</html>\n";
}
}

3. Define the OIDC dependency

./gradlew addExtension --extensions='oidc'

OIDC dependency defines the goodness to do OIDC based auth in your quarkus application.

4. Run the application atleast once

I am running this from intellij, so I can use the gradle plugin,
but you can do it from CLI as well like this.

./gradlew quarkusDev

You’ll see that your project deps are being pulled. You’ll also see some docker related activity in your application logs.

a) If your docker is not running, then you’ll see a failure!
b) If your docker is running, then you’ll see some images being pulled!

Any which ways, when OIDC client is installed, Quarkus by default
tries to use keycloak, and to do so tries to access docker. For now, you can just kill this instance cuz you can’t use it yet.

5. Lets refine our run

We’ll define two application properties with the quarkus prefix.

a) http.port: The port on which your application will run. Defaults
to 8080. Can be overridden by the PORT environment variable.

b) oidc.auth-server-url: I’ll be using google cloud for oauth server.
This config tells quarkus to not depend on keycloak by default.

Run this command now:

PORT=9000 ./gradlew quarkusDev

You’ll see that your web application is now serving requests on port
9000. You can now try by switching off Docker as well! At this point, you won’t see much happening here as this auth-server is not real.

6. Throw in some auth

  • We’ll mark our GreetingResource as Authenticated now.
  • We’ll set the oidc provider to google because we want to use auth from GCloud.
  • We’ll obtain the client_id from GCloud.

Quarkus provides an env variable to set the client ID as well (full doc here), but that is long in name, so we can define the CLIENTID env variable for convenience.

quarkus.oidc.provider=google
quarkus.oidc.client-id=${CLIENTID:client_id}
@Path("/")
@Authenticated
public class GreetingResource

Now when you re-run the application & open the URL then your google auth will show up and give a redirect URI error. You can get around the redirect error by configuring the URL http://localhost:9000/ as your redirect URI.

CLIENTID=xxx.apps.googleusercontent.com PORT=9000 ./gradlew quarkusDev

After configuring the redirect URI as above you’ll get the next error asking you to configure a client secret.

OIDC config suggests multiple secret values. Which one do we
want to go for?

As of now it seems that we can use both the secret options:

a) quarkus.oidc.credentials.secret
b) quarkus.oidc.credentials.client-secret.value

For now I am proceeding with option a) . Now you can try accessing the endpoint localhost:9000 which will take you to the auth flow. Once you authenticate yourself, you will see an error in your Quarkus application!

This error is about inability to fetch the user info.

This error is the only reason why I am writing this article 😅.

7. Verify User Token flow

If you configure debug level logging you’ll notice that our application is able to access the relevant JWT token from the Google IdP but is unable to verify it because we have not given our application the right config. Let’s fix that.

quarkus.oidc.authentication.user-info-required=true

This config instructs our quarkus application to verify the JWT token and inject it into the application.

Voila! If you restart the application, it’ll work 💪 and show a screen with your email.

Happy coding!

--

--

Writer for

Engineer @ toplyne.io. Currently dabbling in Data Platforms & MLOps. Previously part of payments & checkout @ Dunzo & trading systems @ DE Shaw.