Learn Quarkus - OAuth2 / OIDC & JWT
Episode 13 of 24

Learn Quarkus - OAuth2 / OIDC & JWT

This episode covers OAuth2 and OIDC in Quarkus: integration with an external identity provider, implementing JWT authentication and authorization, service-to-service auth with token introspection, and token storage and refresh best practices.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Basic auth is enough for small applications, but modern applications need identity federation: users log in at one place (Google, GitHub, Keycloak) and then access many services. This is where OAuth2 and OpenID Connect (OIDC) come in.

Episode 13 covers Quarkus integration with an OIDC external identity provider, implementing JWT authentication and authorization, service-to-service auth with token introspection, as well as token storage, refresh, and scope best practices.

Quarkus OIDC Integration for External Identity Providers

Adding the Extension

Adding the OIDC extension
./mvnw quarkus:add-extension -Dextensions=oidc

The command ./mvnw quarkus:add-extension -Dextensions=oidc adds OIDC support to your project.

OIDC Configuration

Connect Quarkus to an identity provider (for example Keycloak) via configuration:

OIDC configuration
quarkus.oidc.auth-server-url=https://auth.example.com/realms/demo
quarkus.oidc.client-id=quarkus-app
quarkus.oidc.credentials.secret=client-secret
quarkus.oidc.tls.verification=certificate-validation
  • auth-server-url: the OIDC provider realm endpoint.
  • client-id and credentials.secret: application credentials for the authorization code flow.
  • tls.verification: make sure the server certificate is validated.

Protecting Endpoints

Once configured, endpoints can be protected with configuration only:

Requiring authentication on paths
quarkus.http.auth.permission.authenticated.paths=/api/*
quarkus.http.auth.permission.authenticated.policy=authenticated

This rule rejects every request to /api/* that doesn't carry a valid token from the provider.

Implementing JWT Authentication and Authorization

How JWT Works

A JWT (JSON Web Token) is a token in the header.payload.signature format. The payload contains claims like sub, exp, and roles. The signature guarantees the token hasn't been modified. Quarkus validates the signature using a key from the OIDC provider — without calling the server on every request.

Reading Claims in a Resource

JavaReading JWT claims
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.eclipse.microprofile.jwt.JsonWebToken;
 
@Path("/api/user")
public class UserResource {
 
    @Inject
    JsonWebToken jwt;
 
    @GET
    @RolesAllowed("user")
    public String info() {
        return "Halo " + jwt.getSubject();
    }
}

jwt.getSubject() returns the sub claim — the user's identity. The @RolesAllowed("user") annotation verifies the roles claim in the token.

The Roles Claim

Make sure the identity provider sends the roles claim. In Keycloak, mapping roles into this claim is configured in the client scope. If the claim name is different, map it via configuration:

Mapping the roles claim
quarkus.oidc.roles.claim=roles

Service-to-Service Auth with Token Introspection

Introspection for Opaque Tokens

Not every service uses JWTs. Opaque tokens need to be verified through an introspection endpoint:

Enabling token introspection
quarkus.oidc.token.audience=quarkus-app
quarkus.oidc.token-issuer=https://auth.example.com/realms/demo

When a client sends an opaque token to Authorization: Bearer, Quarkus calls the provider's introspection endpoint to validate it and fetch the claims. This is commonly used for communication between internal services.

The Client Credentials Flow

Service-to-service communication without user intervention uses the client credentials flow:

JavaClient credentials flow
import io.quarkus.oidc.client.OidcClient;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
 
@ApplicationScoped
public class InternalApiClient {
 
    @Inject
    OidcClient oidcClient;
 
    public String panggilServiceInternal() {
        String token = oidcClient.getTokens().await().indefinitely()
            .getAccessToken();
        return kirimRequest(token);
    }
}

oidcClient.getTokens() obtains an access token with client credentials. This token is used to call other internal services — a common pattern in microservices architectures.

Token Storage, Refresh, and Scope Best Practices

Don't Store JWTs in Insecure Storage

In the browser, keep the access token in memory, not in localStorage (which is vulnerable to XSS). For native applications, store it securely in the keychain. On the server, never log tokens — a JWT contains sensitive identity information.

Minimal Scopes

Request the smallest possible scope:

Limiting scopes
quarkus.oidc.scopes=openid,profile

quarkus.oidc.scopes determines which claims are requested from the provider. The less data you request, the smaller your attack surface.

Refresh Tokens and Logout

Access tokens are short-lived (for example 5 minutes); a refresh token obtains a new access token without re-authentication. Quarkus manages this automatically for web-based applications. The golden rule: the refresh token is only sent to the server, never to client-side JavaScript. For logout, call the provider's logout endpoint:

Logout configuration
quarkus.oidc.logout.path=/api/logout
quarkus.oidc.logout.post-logout-path=/

Wrap-Up

Episode 13 brings you to modern security: understanding Quarkus OIDC integration with an external identity provider, implementing JWT authentication and authorization, service-to-service auth with token introspection and the client credentials flow, as well as token storage, refresh, and scope best practices.

Key takeaways:

  • OIDC moves authentication to an external identity provider.
  • JWTs are validated with a signature without calling the server on every request.
  • @RolesAllowed reads the roles claim from the token.
  • Opaque tokens are verified through the introspection endpoint.
  • The client credentials flow for service-to-service communication.
  • Access tokens are stored in memory; refresh tokens only on the server.
  • Scopes are kept minimal to reduce the attack surface.

In episode 14 we'll cover secure microservices and the API gateway — secure microservice patterns with Quarkus, integration with Istio, Envoy, or an API gateway, securing inter-service communication, as well as rate limiting and API policies.

Learn Quarkus - OAuth2 / OIDC & JWT | Learn Quarkus