CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkus--quarkus-oidc-client

Get and refresh access tokens from OpenID Connect providers

Pending
Overview
Eval results
Files

integration.mddocs/

Integration

CDI injection support, JAX-RS client filter integration, and SPI interfaces for extending OIDC client functionality. Provides seamless integration with Quarkus's dependency injection system and REST client ecosystem.

Capabilities

CDI Integration

Dependency injection support for OIDC clients using standard CDI annotations and custom qualifiers for named clients.

/**
 * CDI qualifier annotation for injecting named OIDC clients
 */
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, PARAMETER, METHOD})
public @interface NamedOidcClient {
    /**
     * Name of the OIDC client to inject
     * @return Client name as configured in application properties
     */
    String value();
}

Usage Examples:

import io.quarkus.oidc.client.OidcClient;
import io.quarkus.oidc.client.OidcClients;
import io.quarkus.oidc.client.NamedOidcClient;
import jakarta.inject.Inject;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class TokenService {
    
    // Inject default OIDC client
    @Inject
    OidcClient defaultClient;
    
    // Inject OIDC clients factory
    @Inject
    OidcClients oidcClients;
    
    // Inject named OIDC client using qualifier
    @Inject
    @NamedOidcClient("auth-provider")
    OidcClient authProviderClient;
    
    // Inject named OIDC client for API access
    @Inject
    @NamedOidcClient("api-client")
    OidcClient apiClient;
    
    public void useInjectedClients() {
        // Use default client
        Uni<Tokens> defaultTokens = defaultClient.getTokens();
        
        // Use named clients
        Uni<Tokens> authTokens = authProviderClient.getTokens();
        Uni<Tokens> apiTokens = apiClient.getTokens();
        
        // Use factory for dynamic client access
        OidcClient dynamicClient = oidcClients.getClient("dynamic-provider");
        Uni<Tokens> dynamicTokens = dynamicClient.getTokens();
    }
}

Configuration for Named Clients:

# Default client
quarkus.oidc-client.auth-server-url=https://default.example.com
quarkus.oidc-client.client-id=default-client
quarkus.oidc-client.credentials.secret=default-secret

# Named client: auth-provider
quarkus.oidc-client.auth-provider.auth-server-url=https://auth.example.com
quarkus.oidc-client.auth-provider.client-id=auth-client
quarkus.oidc-client.auth-provider.credentials.secret=auth-secret

# Named client: api-client
quarkus.oidc-client.api-client.auth-server-url=https://api.example.com
quarkus.oidc-client.api-client.client-id=api-client
quarkus.oidc-client.api-client.credentials.secret=api-secret
quarkus.oidc-client.api-client.grant.type=client

JAX-RS Integration

Automatic token injection for REST clients using filter annotations. Enables seamless authentication for outbound HTTP requests.

/**
 * Annotation for JAX-RS client filters to automatically inject OIDC tokens
 */
@Target({TYPE})
@Retention(RUNTIME)
public @interface OidcClientFilter {
    /**
     * Name of the OIDC client to use for token acquisition
     * Empty string uses the default client
     * @return OIDC client name
     */
    String value() default "";
}

Usage Examples:

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.filter.OidcClientFilter;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

// REST client using default OIDC client
@RegisterRestClient(configKey = "api-service")
@OidcClientFilter
@Path("/api")
public interface ApiServiceClient {
    
    @GET
    @Path("/users")
    @Produces(MediaType.APPLICATION_JSON)
    List<User> getUsers();
    
    @GET
    @Path("/protected-resource")
    @Produces(MediaType.APPLICATION_JSON)
    ProtectedData getProtectedData();
}

// REST client using named OIDC client
@RegisterRestClient(configKey = "admin-service")
@OidcClientFilter("admin-client")
@Path("/admin")
public interface AdminServiceClient {
    
    @GET
    @Path("/config")
    @Produces(MediaType.APPLICATION_JSON)
    AdminConfig getConfig();
    
    @POST
    @Path("/users")
    @Consumes(MediaType.APPLICATION_JSON)
    void createUser(User user);
}

Service Usage:

import org.eclipse.microprofile.rest.client.inject.RestClient;
import jakarta.inject.Inject;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class BusinessService {
    
    @Inject
    @RestClient
    ApiServiceClient apiClient;
    
    @Inject
    @RestClient
    AdminServiceClient adminClient;
    
    public void performBusinessOperations() {
        // These calls will automatically include OIDC tokens
        List<User> users = apiClient.getUsers(); // Uses default client
        AdminConfig config = adminClient.getConfig(); // Uses admin-client
        
        // Process data...
    }
}

REST Client Configuration:

# API service client configuration
quarkus.rest-client.api-service.url=https://api.example.com
quarkus.rest-client.api-service.connection-timeout=5000
quarkus.rest-client.api-service.read-timeout=10000

# Admin service client configuration  
quarkus.rest-client.admin-service.url=https://admin.example.com
quarkus.rest-client.admin-service.connection-timeout=3000
quarkus.rest-client.admin-service.read-timeout=15000

# OIDC clients for the filters
quarkus.oidc-client.auth-server-url=https://auth.example.com
quarkus.oidc-client.client-id=api-client
quarkus.oidc-client.credentials.secret=api-secret

quarkus.oidc-client.admin-client.auth-server-url=https://admin-auth.example.com
quarkus.oidc-client.admin-client.client-id=admin-client
quarkus.oidc-client.admin-client.credentials.secret=admin-secret

SPI Integration

Service Provider Interface for custom token providers and OIDC client extensions.

/**
 * SPI interface for OIDC clients that can acquire and refresh access tokens automatically
 */
public interface TokenProvider {
    /**
     * Get a valid access token
     * Implementations should handle token refresh automatically if needed
     * @return Uni<String> containing a valid access token
     */
    Uni<String> getAccessToken();
}

Usage Examples:

import io.quarkus.oidc.client.spi.TokenProvider;
import io.quarkus.oidc.client.OidcClient;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

/**
 * Custom token provider implementation
 */
@ApplicationScoped
public class CustomTokenProvider implements TokenProvider {
    
    @Inject
    OidcClient oidcClient;
    
    private volatile String cachedToken;
    private volatile long tokenExpiresAt;
    
    @Override
    public Uni<String> getAccessToken() {
        // Check if cached token is still valid
        if (cachedToken != null && System.currentTimeMillis() < tokenExpiresAt) {
            return Uni.createFrom().item(cachedToken);
        }
        
        // Get new token
        return oidcClient.getTokens()
            .onItem().invoke(tokens -> {
                cachedToken = tokens.getAccessToken();
                
                // Cache for 90% of the token lifetime
                Long expiresAt = tokens.getAccessTokenExpiresAt();
                if (expiresAt != null) {
                    long now = System.currentTimeMillis() / 1000;
                    long lifetime = expiresAt - now;
                    tokenExpiresAt = (now + (long)(lifetime * 0.9)) * 1000;
                } else {
                    // Default to 1 hour if no expiration provided
                    tokenExpiresAt = System.currentTimeMillis() + 3600000;
                }
            })
            .map(tokens -> tokens.getAccessToken());
    }
}

/**
 * Service using custom token provider
 */
@ApplicationScoped
public class SecureService {
    
    @Inject
    TokenProvider tokenProvider;
    
    public Uni<String> callProtectedApi() {
        return tokenProvider.getAccessToken()
            .flatMap(token -> {
                // Use token to call protected API
                return callApiWithToken(token);
            });
    }
    
    private Uni<String> callApiWithToken(String token) {
        // Implementation for calling API with token
        // ...
        return Uni.createFrom().item("API response");
    }
}

Advanced Integration Patterns

Complex integration scenarios combining multiple OIDC clients and advanced token management.

import io.quarkus.oidc.client.OidcClient;
import io.quarkus.oidc.client.OidcClients;
import io.quarkus.oidc.client.NamedOidcClient;
import io.quarkus.oidc.client.spi.TokenProvider;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Multi-tenant token provider supporting different OIDC providers per tenant
 */
@ApplicationScoped
public class MultiTenantTokenProvider implements TokenProvider {
    
    @Inject
    OidcClients oidcClients;
    
    private final Map<String, String> tenantTokens = new ConcurrentHashMap<>();
    
    public Uni<String> getAccessTokenForTenant(String tenantId) {
        // Get tenant-specific OIDC client
        OidcClient tenantClient = oidcClients.getClient(tenantId);
        
        return tenantClient.getTokens()
            .onItem().invoke(tokens -> {
                tenantTokens.put(tenantId, tokens.getAccessToken());
            })
            .map(tokens -> tokens.getAccessToken());
    }
    
    @Override
    public Uni<String> getAccessToken() {
        // Default implementation for single-tenant scenarios
        return oidcClients.getClient().getTokens()
            .map(tokens -> tokens.getAccessToken());
    }
}

/**
 * Token refresh service with circuit breaker pattern
 */
@ApplicationScoped
public class RobustTokenService {
    
    @Inject
    @NamedOidcClient("primary")
    OidcClient primaryClient;
    
    @Inject
    @NamedOidcClient("fallback")
    OidcClient fallbackClient;
    
    private volatile boolean primaryHealthy = true;
    private volatile long lastFailureTime = 0;
    private static final long CIRCUIT_BREAKER_TIMEOUT = 60000; // 1 minute
    
    public Uni<String> getAccessTokenWithFallback() {
        if (primaryHealthy || shouldTryPrimary()) {
            return primaryClient.getTokens()
                .onItem().invoke(() -> {
                    primaryHealthy = true;
                })
                .onFailure().invoke(throwable -> {
                    primaryHealthy = false;
                    lastFailureTime = System.currentTimeMillis();
                })
                .onFailure().recoverWithUni(throwable -> {
                    System.err.println("Primary client failed, using fallback: " + 
                        throwable.getMessage());
                    return fallbackClient.getTokens();
                })
                .map(tokens -> tokens.getAccessToken());
        } else {
            return fallbackClient.getTokens()
                .map(tokens -> tokens.getAccessToken());
        }
    }
    
    private boolean shouldTryPrimary() {
        return System.currentTimeMillis() - lastFailureTime > CIRCUIT_BREAKER_TIMEOUT;
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkus--quarkus-oidc-client

docs

client-interface.md

configuration.md

index.md

integration.md

token-management.md

tile.json