CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-core

Core runtime module for Quarkus LangChain4j integration with declarative AI services, guardrails, and observability

Overview
Eval results
Files

authentication.mddocs/

Authentication

The authentication framework provides flexible authentication credential management for AI model providers. Implement the ModelAuthProvider interface to supply access tokens, API keys, or other authorization headers for model requests.

Core Imports

import io.quarkiverse.langchain4j.auth.ModelAuthProvider;
import io.quarkiverse.langchain4j.ModelName;
import jakarta.enterprise.context.ApplicationScoped;

ModelAuthProvider Interface

package io.quarkiverse.langchain4j.auth;

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public interface ModelAuthProvider {
    String getAuthorization(Input input);
    
    static Optional<ModelAuthProvider> resolve(String modelName);
    
    interface Input {
        String method();
        URI uri();
        Map<String, List<Object>> headers();
    }
}

Methods

getAuthorization(Input)

String getAuthorization(Input input);

Provides the authorization header value for model provider requests.

Parameters:

  • input: Request context containing HTTP method, URI, and headers

Returns:

  • Authorization scheme + value (e.g., "Bearer token123", "Api-Key sk-...")
  • null if no authorization is needed

resolve(String) (Static)

static Optional<ModelAuthProvider> resolve(String modelName);

Resolves the appropriate ModelAuthProvider for a given model name.

Parameters:

  • modelName: The name of the model configuration

Returns:

  • Optional containing the matching provider, or empty if none found

Resolution Logic:

  1. Looks for provider qualified with @ModelName(modelName)
  2. Falls back to global provider (no @ModelName qualifier)
  3. Returns empty if no provider found

Input Interface

public interface Input {
    String method();
    URI uri();
    Map<String, List<Object>> headers();
}

Provides context about the HTTP request being made to the model provider.

Methods:

  • method(): HTTP method (GET, POST, etc.)
  • uri(): Full request URI
  • headers(): Request headers map

Usage Examples

Basic API Key Provider

import io.quarkiverse.langchain4j.auth.ModelAuthProvider;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class OpenAIAuthProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        // Get API key from configuration or secret store
        String apiKey = System.getenv("OPENAI_API_KEY");
        return "Bearer " + apiKey;
    }
}

Named Model Provider

import io.quarkiverse.langchain4j.auth.ModelAuthProvider;
import io.quarkiverse.langchain4j.ModelName;
import jakarta.enterprise.context.ApplicationScoped;

// Provider for a specific named model
@ApplicationScoped
@ModelName("gpt4")
public class GPT4AuthProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        return "Bearer " + System.getenv("OPENAI_GPT4_API_KEY");
    }
}

// Provider for another named model
@ApplicationScoped
@ModelName("claude")
public class ClaudeAuthProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        return "x-api-key " + System.getenv("ANTHROPIC_API_KEY");
    }
}

// Global fallback provider
@ApplicationScoped
public class DefaultAuthProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        return "Bearer " + System.getenv("DEFAULT_API_KEY");
    }
}

Dynamic Token Provider

import jakarta.inject.Inject;

@ApplicationScoped
public class DynamicTokenProvider implements ModelAuthProvider {
    @Inject
    TokenService tokenService;
    
    @Override
    public String getAuthorization(Input input) {
        // Fetch fresh token on each request
        String token = tokenService.getAccessToken();
        return "Bearer " + token;
    }
}

OAuth2 Token Provider

import jakarta.enterprise.context.ApplicationScoped;
import java.time.Instant;
import java.util.concurrent.locks.ReentrantLock;

@ApplicationScoped
public class OAuth2TokenProvider implements ModelAuthProvider {
    private String cachedToken;
    private Instant tokenExpiry;
    private final ReentrantLock lock = new ReentrantLock();
    
    @Override
    public String getAuthorization(Input input) {
        String token = getCachedOrFreshToken();
        return "Bearer " + token;
    }
    
    private String getCachedOrFreshToken() {
        if (cachedToken != null && Instant.now().isBefore(tokenExpiry)) {
            return cachedToken;
        }
        
        lock.lock();
        try {
            // Double-check after acquiring lock
            if (cachedToken != null && Instant.now().isBefore(tokenExpiry)) {
                return cachedToken;
            }
            
            // Fetch new token
            OAuth2Token token = oauth2Client.requestToken();
            cachedToken = token.accessToken();
            tokenExpiry = Instant.now().plusSeconds(token.expiresIn() - 60); // 60s buffer
            
            return cachedToken;
        } finally {
            lock.unlock();
        }
    }
}

Multi-Tenant Provider

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class MultiTenantAuthProvider implements ModelAuthProvider {
    @Inject
    TenantContext tenantContext;
    
    @Inject
    ApiKeyStore apiKeyStore;
    
    @Override
    public String getAuthorization(Input input) {
        String tenantId = tenantContext.getCurrentTenant();
        String apiKey = apiKeyStore.getApiKey(tenantId);
        return "Bearer " + apiKey;
    }
}

Request-Based Authorization

@ApplicationScoped
public class RequestBasedAuthProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        // Different auth based on endpoint
        if (input.uri().getPath().contains("/chat")) {
            return "Bearer " + getChatApiKey();
        } else if (input.uri().getPath().contains("/embeddings")) {
            return "Bearer " + getEmbeddingsApiKey();
        }
        
        return "Bearer " + getDefaultApiKey();
    }
}

Secret Management Integration

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class SecretManagerAuthProvider implements ModelAuthProvider {
    @Inject
    SecretManager secretManager;
    
    @Override
    public String getAuthorization(Input input) {
        // Retrieve API key from secret manager (Vault, AWS Secrets Manager, etc.)
        String apiKey = secretManager.getSecret("ai-model-api-key");
        return "Bearer " + apiKey;
    }
}

Conditional Authorization

@ApplicationScoped
public class ConditionalAuthProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        // Some requests might not need auth (e.g., health checks)
        if (input.uri().getPath().equals("/health")) {
            return null; // No authorization needed
        }
        
        return "Bearer " + getApiKey();
    }
}

Header Inspection

@ApplicationScoped
public class HeaderInspectingProvider implements ModelAuthProvider {
    @Override
    public String getAuthorization(Input input) {
        // Inspect existing headers
        Map<String, List<Object>> headers = input.headers();
        
        // Add different auth based on request characteristics
        if (headers.containsKey("X-Special-Request")) {
            return "Bearer " + getSpecialApiKey();
        }
        
        return "Bearer " + getStandardApiKey();
    }
}

Programmatic Provider Resolution

import io.quarkiverse.langchain4j.auth.ModelAuthProvider;
import java.util.Optional;

@ApplicationScoped
public class ModelService {
    public void useModel(String modelName) {
        Optional<ModelAuthProvider> provider = ModelAuthProvider.resolve(modelName);
        
        if (provider.isPresent()) {
            // Provider found for this model
            ModelAuthProvider authProvider = provider.get();
            // Use provider...
        } else {
            // No provider found, handle accordingly
            throw new IllegalStateException("No auth provider for model: " + modelName);
        }
    }
}

Comprehensive Example

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkiverse.langchain4j.auth.ModelAuthProvider;
import io.quarkiverse.langchain4j.ModelName;
import org.jboss.logging.Logger;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

// Global provider with token caching and monitoring
@ApplicationScoped
public class ProductionAuthProvider implements ModelAuthProvider {
    private static final Logger LOG = Logger.getLogger(ProductionAuthProvider.class);
    
    @Inject
    SecretManager secretManager;
    
    @Inject
    MetricsService metrics;
    
    private final Map<String, TokenCache> tokenCache = new ConcurrentHashMap<>();
    
    @Override
    public String getAuthorization(Input input) {
        String apiKey = getCachedToken();
        
        // Log authorization request (without exposing key)
        LOG.debugf("Providing authorization for: %s %s", 
            input.method(), input.uri().getPath());
        
        // Track auth requests
        metrics.incrementCounter("model.auth.requests");
        
        return "Bearer " + apiKey;
    }
    
    private String getCachedToken() {
        String cacheKey = "default";
        TokenCache cache = tokenCache.computeIfAbsent(cacheKey, 
            k -> new TokenCache());
        
        if (cache.isValid()) {
            metrics.incrementCounter("model.auth.cache.hits");
            return cache.token;
        }
        
        synchronized (cache) {
            // Double-check after lock
            if (cache.isValid()) {
                return cache.token;
            }
            
            // Fetch fresh token
            metrics.incrementCounter("model.auth.cache.misses");
            String token = secretManager.getSecret("ai-model-api-key");
            cache.update(token, Instant.now().plusSeconds(3600));
            
            return token;
        }
    }
    
    private static class TokenCache {
        String token;
        Instant expiry;
        
        boolean isValid() {
            return token != null && Instant.now().isBefore(expiry);
        }
        
        void update(String token, Instant expiry) {
            this.token = token;
            this.expiry = expiry;
        }
    }
}

// Named provider for premium model with special auth
@ApplicationScoped
@ModelName("premium-gpt4")
public class PremiumModelAuthProvider implements ModelAuthProvider {
    private static final Logger LOG = Logger.getLogger(PremiumModelAuthProvider.class);
    
    @Inject
    PremiumAuthService premiumAuth;
    
    @Override
    public String getAuthorization(Input input) {
        LOG.info("Using premium model authentication");
        
        // Premium models use different auth mechanism
        String premiumToken = premiumAuth.getPremiumToken();
        return "X-Premium-Token " + premiumToken;
    }
}

Configuration

While ModelAuthProvider implementations can retrieve credentials from any source, typical configuration might include:

# Environment variables
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...

# Or Quarkus config
quarkus.langchain4j.openai.api-key=${OPENAI_API_KEY}

Notes

  • CDI Scoped: Implementations should typically be @ApplicationScoped
  • Model-Specific: Use @ModelName qualifier for model-specific providers
  • Global Fallback: Provider without @ModelName serves as fallback
  • Return null: Return null when no authorization is needed
  • Thread Safety: Implementations should be thread-safe
  • Token Caching: Consider caching tokens to avoid excessive secret manager calls
  • Security: Never log or expose actual credentials
  • Header Format: Return complete authorization header value including scheme

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-core@1.7.0

docs

ai-services.md

authentication.md

cost-estimation.md

guardrails.md

index.md

media-content.md

memory.md

observability.md

response-augmentation.md

tools.md

tile.json