0
# Integration
1
2
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.
3
4
## Capabilities
5
6
### CDI Integration
7
8
Dependency injection support for OIDC clients using standard CDI annotations and custom qualifiers for named clients.
9
10
```java { .api }
11
/**
12
* CDI qualifier annotation for injecting named OIDC clients
13
*/
14
@Qualifier
15
@Retention(RUNTIME)
16
@Target({FIELD, PARAMETER, METHOD})
17
public @interface NamedOidcClient {
18
/**
19
* Name of the OIDC client to inject
20
* @return Client name as configured in application properties
21
*/
22
String value();
23
}
24
```
25
26
**Usage Examples:**
27
28
```java
29
import io.quarkus.oidc.client.OidcClient;
30
import io.quarkus.oidc.client.OidcClients;
31
import io.quarkus.oidc.client.NamedOidcClient;
32
import jakarta.inject.Inject;
33
import jakarta.enterprise.context.ApplicationScoped;
34
35
@ApplicationScoped
36
public class TokenService {
37
38
// Inject default OIDC client
39
@Inject
40
OidcClient defaultClient;
41
42
// Inject OIDC clients factory
43
@Inject
44
OidcClients oidcClients;
45
46
// Inject named OIDC client using qualifier
47
@Inject
48
@NamedOidcClient("auth-provider")
49
OidcClient authProviderClient;
50
51
// Inject named OIDC client for API access
52
@Inject
53
@NamedOidcClient("api-client")
54
OidcClient apiClient;
55
56
public void useInjectedClients() {
57
// Use default client
58
Uni<Tokens> defaultTokens = defaultClient.getTokens();
59
60
// Use named clients
61
Uni<Tokens> authTokens = authProviderClient.getTokens();
62
Uni<Tokens> apiTokens = apiClient.getTokens();
63
64
// Use factory for dynamic client access
65
OidcClient dynamicClient = oidcClients.getClient("dynamic-provider");
66
Uni<Tokens> dynamicTokens = dynamicClient.getTokens();
67
}
68
}
69
```
70
71
**Configuration for Named Clients:**
72
73
```properties
74
# Default client
75
quarkus.oidc-client.auth-server-url=https://default.example.com
76
quarkus.oidc-client.client-id=default-client
77
quarkus.oidc-client.credentials.secret=default-secret
78
79
# Named client: auth-provider
80
quarkus.oidc-client.auth-provider.auth-server-url=https://auth.example.com
81
quarkus.oidc-client.auth-provider.client-id=auth-client
82
quarkus.oidc-client.auth-provider.credentials.secret=auth-secret
83
84
# Named client: api-client
85
quarkus.oidc-client.api-client.auth-server-url=https://api.example.com
86
quarkus.oidc-client.api-client.client-id=api-client
87
quarkus.oidc-client.api-client.credentials.secret=api-secret
88
quarkus.oidc-client.api-client.grant.type=client
89
```
90
91
### JAX-RS Integration
92
93
Automatic token injection for REST clients using filter annotations. Enables seamless authentication for outbound HTTP requests.
94
95
```java { .api }
96
/**
97
* Annotation for JAX-RS client filters to automatically inject OIDC tokens
98
*/
99
@Target({TYPE})
100
@Retention(RUNTIME)
101
public @interface OidcClientFilter {
102
/**
103
* Name of the OIDC client to use for token acquisition
104
* Empty string uses the default client
105
* @return OIDC client name
106
*/
107
String value() default "";
108
}
109
```
110
111
**Usage Examples:**
112
113
```java
114
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
115
import io.quarkus.oidc.client.filter.OidcClientFilter;
116
import jakarta.ws.rs.GET;
117
import jakarta.ws.rs.Path;
118
import jakarta.ws.rs.Produces;
119
import jakarta.ws.rs.core.MediaType;
120
121
// REST client using default OIDC client
122
@RegisterRestClient(configKey = "api-service")
123
@OidcClientFilter
124
@Path("/api")
125
public interface ApiServiceClient {
126
127
@GET
128
@Path("/users")
129
@Produces(MediaType.APPLICATION_JSON)
130
List<User> getUsers();
131
132
@GET
133
@Path("/protected-resource")
134
@Produces(MediaType.APPLICATION_JSON)
135
ProtectedData getProtectedData();
136
}
137
138
// REST client using named OIDC client
139
@RegisterRestClient(configKey = "admin-service")
140
@OidcClientFilter("admin-client")
141
@Path("/admin")
142
public interface AdminServiceClient {
143
144
@GET
145
@Path("/config")
146
@Produces(MediaType.APPLICATION_JSON)
147
AdminConfig getConfig();
148
149
@POST
150
@Path("/users")
151
@Consumes(MediaType.APPLICATION_JSON)
152
void createUser(User user);
153
}
154
```
155
156
**Service Usage:**
157
158
```java
159
import org.eclipse.microprofile.rest.client.inject.RestClient;
160
import jakarta.inject.Inject;
161
import jakarta.enterprise.context.ApplicationScoped;
162
163
@ApplicationScoped
164
public class BusinessService {
165
166
@Inject
167
@RestClient
168
ApiServiceClient apiClient;
169
170
@Inject
171
@RestClient
172
AdminServiceClient adminClient;
173
174
public void performBusinessOperations() {
175
// These calls will automatically include OIDC tokens
176
List<User> users = apiClient.getUsers(); // Uses default client
177
AdminConfig config = adminClient.getConfig(); // Uses admin-client
178
179
// Process data...
180
}
181
}
182
```
183
184
**REST Client Configuration:**
185
186
```properties
187
# API service client configuration
188
quarkus.rest-client.api-service.url=https://api.example.com
189
quarkus.rest-client.api-service.connection-timeout=5000
190
quarkus.rest-client.api-service.read-timeout=10000
191
192
# Admin service client configuration
193
quarkus.rest-client.admin-service.url=https://admin.example.com
194
quarkus.rest-client.admin-service.connection-timeout=3000
195
quarkus.rest-client.admin-service.read-timeout=15000
196
197
# OIDC clients for the filters
198
quarkus.oidc-client.auth-server-url=https://auth.example.com
199
quarkus.oidc-client.client-id=api-client
200
quarkus.oidc-client.credentials.secret=api-secret
201
202
quarkus.oidc-client.admin-client.auth-server-url=https://admin-auth.example.com
203
quarkus.oidc-client.admin-client.client-id=admin-client
204
quarkus.oidc-client.admin-client.credentials.secret=admin-secret
205
```
206
207
### SPI Integration
208
209
Service Provider Interface for custom token providers and OIDC client extensions.
210
211
```java { .api }
212
/**
213
* SPI interface for OIDC clients that can acquire and refresh access tokens automatically
214
*/
215
public interface TokenProvider {
216
/**
217
* Get a valid access token
218
* Implementations should handle token refresh automatically if needed
219
* @return Uni<String> containing a valid access token
220
*/
221
Uni<String> getAccessToken();
222
}
223
```
224
225
**Usage Examples:**
226
227
```java
228
import io.quarkus.oidc.client.spi.TokenProvider;
229
import io.quarkus.oidc.client.OidcClient;
230
import io.smallrye.mutiny.Uni;
231
import jakarta.enterprise.context.ApplicationScoped;
232
import jakarta.inject.Inject;
233
234
/**
235
* Custom token provider implementation
236
*/
237
@ApplicationScoped
238
public class CustomTokenProvider implements TokenProvider {
239
240
@Inject
241
OidcClient oidcClient;
242
243
private volatile String cachedToken;
244
private volatile long tokenExpiresAt;
245
246
@Override
247
public Uni<String> getAccessToken() {
248
// Check if cached token is still valid
249
if (cachedToken != null && System.currentTimeMillis() < tokenExpiresAt) {
250
return Uni.createFrom().item(cachedToken);
251
}
252
253
// Get new token
254
return oidcClient.getTokens()
255
.onItem().invoke(tokens -> {
256
cachedToken = tokens.getAccessToken();
257
258
// Cache for 90% of the token lifetime
259
Long expiresAt = tokens.getAccessTokenExpiresAt();
260
if (expiresAt != null) {
261
long now = System.currentTimeMillis() / 1000;
262
long lifetime = expiresAt - now;
263
tokenExpiresAt = (now + (long)(lifetime * 0.9)) * 1000;
264
} else {
265
// Default to 1 hour if no expiration provided
266
tokenExpiresAt = System.currentTimeMillis() + 3600000;
267
}
268
})
269
.map(tokens -> tokens.getAccessToken());
270
}
271
}
272
273
/**
274
* Service using custom token provider
275
*/
276
@ApplicationScoped
277
public class SecureService {
278
279
@Inject
280
TokenProvider tokenProvider;
281
282
public Uni<String> callProtectedApi() {
283
return tokenProvider.getAccessToken()
284
.flatMap(token -> {
285
// Use token to call protected API
286
return callApiWithToken(token);
287
});
288
}
289
290
private Uni<String> callApiWithToken(String token) {
291
// Implementation for calling API with token
292
// ...
293
return Uni.createFrom().item("API response");
294
}
295
}
296
```
297
298
### Advanced Integration Patterns
299
300
Complex integration scenarios combining multiple OIDC clients and advanced token management.
301
302
```java
303
import io.quarkus.oidc.client.OidcClient;
304
import io.quarkus.oidc.client.OidcClients;
305
import io.quarkus.oidc.client.NamedOidcClient;
306
import io.quarkus.oidc.client.spi.TokenProvider;
307
import jakarta.enterprise.context.ApplicationScoped;
308
import jakarta.inject.Inject;
309
import java.util.Map;
310
import java.util.concurrent.ConcurrentHashMap;
311
312
/**
313
* Multi-tenant token provider supporting different OIDC providers per tenant
314
*/
315
@ApplicationScoped
316
public class MultiTenantTokenProvider implements TokenProvider {
317
318
@Inject
319
OidcClients oidcClients;
320
321
private final Map<String, String> tenantTokens = new ConcurrentHashMap<>();
322
323
public Uni<String> getAccessTokenForTenant(String tenantId) {
324
// Get tenant-specific OIDC client
325
OidcClient tenantClient = oidcClients.getClient(tenantId);
326
327
return tenantClient.getTokens()
328
.onItem().invoke(tokens -> {
329
tenantTokens.put(tenantId, tokens.getAccessToken());
330
})
331
.map(tokens -> tokens.getAccessToken());
332
}
333
334
@Override
335
public Uni<String> getAccessToken() {
336
// Default implementation for single-tenant scenarios
337
return oidcClients.getClient().getTokens()
338
.map(tokens -> tokens.getAccessToken());
339
}
340
}
341
342
/**
343
* Token refresh service with circuit breaker pattern
344
*/
345
@ApplicationScoped
346
public class RobustTokenService {
347
348
@Inject
349
@NamedOidcClient("primary")
350
OidcClient primaryClient;
351
352
@Inject
353
@NamedOidcClient("fallback")
354
OidcClient fallbackClient;
355
356
private volatile boolean primaryHealthy = true;
357
private volatile long lastFailureTime = 0;
358
private static final long CIRCUIT_BREAKER_TIMEOUT = 60000; // 1 minute
359
360
public Uni<String> getAccessTokenWithFallback() {
361
if (primaryHealthy || shouldTryPrimary()) {
362
return primaryClient.getTokens()
363
.onItem().invoke(() -> {
364
primaryHealthy = true;
365
})
366
.onFailure().invoke(throwable -> {
367
primaryHealthy = false;
368
lastFailureTime = System.currentTimeMillis();
369
})
370
.onFailure().recoverWithUni(throwable -> {
371
System.err.println("Primary client failed, using fallback: " +
372
throwable.getMessage());
373
return fallbackClient.getTokens();
374
})
375
.map(tokens -> tokens.getAccessToken());
376
} else {
377
return fallbackClient.getTokens()
378
.map(tokens -> tokens.getAccessToken());
379
}
380
}
381
382
private boolean shouldTryPrimary() {
383
return System.currentTimeMillis() - lastFailureTime > CIRCUIT_BREAKER_TIMEOUT;
384
}
385
}
386
```