0
# Token Management
1
2
Token container and management functionality providing access to tokens, expiration tracking, and automatic refresh capabilities. The `Tokens` class encapsulates access and refresh tokens along with metadata for intelligent token lifecycle management.
3
4
## Capabilities
5
6
### Tokens Class
7
8
Container class for access and refresh tokens returned from OIDC token grant requests. Provides comprehensive token metadata and expiration tracking capabilities.
9
10
```java { .api }
11
/**
12
* Container for access and refresh tokens with metadata
13
*/
14
public class Tokens {
15
/**
16
* Construct a Tokens instance with full token information
17
* @param accessToken The access token string
18
* @param accessTokenExpiresAt Timestamp when access token expires (epoch seconds)
19
* @param refreshTokenTimeSkewDuration Time skew duration for refresh token operations
20
* @param refreshToken The refresh token string (may be null)
21
* @param refreshTokenExpiresAt Timestamp when refresh token expires (epoch seconds, may be null)
22
* @param grantResponse The complete JSON response from the token grant
23
* @param clientId The client ID used for the token request
24
*/
25
public Tokens(String accessToken, Long accessTokenExpiresAt, Duration refreshTokenTimeSkewDuration,
26
String refreshToken, Long refreshTokenExpiresAt, JsonObject grantResponse, String clientId);
27
28
/**
29
* Get the access token string
30
* @return The access token
31
*/
32
public String getAccessToken();
33
34
/**
35
* Get the refresh token string
36
* @return The refresh token, or null if not available
37
*/
38
public String getRefreshToken();
39
40
/**
41
* Get the client ID used for token acquisition
42
* @return The client ID
43
*/
44
public String getClientId();
45
46
/**
47
* Get a property from the original grant response
48
* @param propertyName Name of the property to retrieve
49
* @return The property value as a String, or null if not found
50
*/
51
public String get(String propertyName);
52
53
/**
54
* Get the access token expiration timestamp
55
* @return Epoch seconds when access token expires, or null if not specified
56
*/
57
public Long getAccessTokenExpiresAt();
58
59
/**
60
* Get the refresh token time skew in seconds
61
* @return Time skew in seconds, or null if not specified
62
*/
63
public Long getRefreshTokenTimeSkew();
64
65
/**
66
* Check if the access token has expired
67
* @return true if access token is expired, false otherwise
68
*/
69
public boolean isAccessTokenExpired();
70
71
/**
72
* Check if the refresh token has expired
73
* @return true if refresh token is expired, false otherwise
74
*/
75
public boolean isRefreshTokenExpired();
76
77
/**
78
* Check if access token should be proactively refreshed
79
* Considers the refresh interval and time skew to determine if token
80
* should be refreshed before it actually expires
81
* @return true if token should be refreshed, false otherwise
82
*/
83
public boolean isAccessTokenWithinRefreshInterval();
84
}
85
```
86
87
**Usage Examples:**
88
89
```java
90
import io.quarkus.oidc.client.Tokens;
91
import io.quarkus.oidc.client.OidcClient;
92
import io.smallrye.mutiny.Uni;
93
import jakarta.enterprise.context.ApplicationScoped;
94
import jakarta.inject.Inject;
95
import java.time.Instant;
96
97
@ApplicationScoped
98
public class TokenManager {
99
100
@Inject
101
OidcClient oidcClient;
102
103
public void manageTokens() {
104
// Get initial tokens
105
Uni<Tokens> tokensUni = oidcClient.getTokens();
106
107
tokensUni.subscribe().with(tokens -> {
108
// Access token information
109
String accessToken = tokens.getAccessToken();
110
Long expiresAt = tokens.getAccessTokenExpiresAt();
111
112
System.out.println("Access token: " + accessToken);
113
System.out.println("Expires at: " +
114
(expiresAt != null ? Instant.ofEpochSecond(expiresAt) : "Never"));
115
116
// Check token status
117
if (tokens.isAccessTokenExpired()) {
118
System.out.println("Access token has expired");
119
} else if (tokens.isAccessTokenWithinRefreshInterval()) {
120
System.out.println("Access token should be refreshed soon");
121
122
// Refresh token if available
123
String refreshToken = tokens.getRefreshToken();
124
if (refreshToken != null && !tokens.isRefreshTokenExpired()) {
125
Uni<Tokens> refreshedTokens = oidcClient.refreshTokens(refreshToken);
126
// Handle refreshed tokens...
127
}
128
}
129
130
// Access additional properties from grant response
131
String scope = tokens.get("scope");
132
String tokenType = tokens.get("token_type");
133
System.out.println("Scope: " + scope);
134
System.out.println("Token type: " + tokenType);
135
});
136
}
137
}
138
```
139
140
### Token Lifecycle Management
141
142
Comprehensive example showing token lifecycle management with automatic refresh and error handling.
143
144
```java
145
import io.quarkus.oidc.client.Tokens;
146
import io.quarkus.oidc.client.OidcClient;
147
import io.quarkus.oidc.client.OidcClientException;
148
import io.smallrye.mutiny.Uni;
149
import jakarta.enterprise.context.ApplicationScoped;
150
import jakarta.inject.Inject;
151
import java.time.Instant;
152
import java.util.concurrent.atomic.AtomicReference;
153
154
@ApplicationScoped
155
public class TokenLifecycleManager {
156
157
@Inject
158
OidcClient oidcClient;
159
160
private final AtomicReference<Tokens> currentTokens = new AtomicReference<>();
161
162
/**
163
* Get a valid access token, refreshing if necessary
164
*/
165
public Uni<String> getValidAccessToken() {
166
Tokens tokens = currentTokens.get();
167
168
if (tokens == null) {
169
// No tokens yet, get initial tokens
170
return obtainInitialTokens();
171
} else if (tokens.isAccessTokenExpired()) {
172
// Token expired, must refresh
173
return refreshTokens(tokens);
174
} else if (tokens.isAccessTokenWithinRefreshInterval()) {
175
// Token should be refreshed proactively
176
return refreshTokensProactively(tokens);
177
} else {
178
// Token is still valid
179
return Uni.createFrom().item(tokens.getAccessToken());
180
}
181
}
182
183
private Uni<String> obtainInitialTokens() {
184
return oidcClient.getTokens()
185
.onItem().invoke(tokens -> {
186
currentTokens.set(tokens);
187
logTokenInfo("Obtained initial tokens", tokens);
188
})
189
.map(Tokens::getAccessToken)
190
.onFailure().invoke(throwable ->
191
System.err.println("Failed to obtain initial tokens: " + throwable.getMessage())
192
);
193
}
194
195
private Uni<String> refreshTokens(Tokens expiredTokens) {
196
String refreshToken = expiredTokens.getRefreshToken();
197
198
if (refreshToken == null || expiredTokens.isRefreshTokenExpired()) {
199
// No refresh token or refresh token expired, get new tokens
200
return obtainInitialTokens();
201
}
202
203
return oidcClient.refreshTokens(refreshToken)
204
.onItem().invoke(tokens -> {
205
currentTokens.set(tokens);
206
logTokenInfo("Refreshed expired tokens", tokens);
207
})
208
.map(Tokens::getAccessToken)
209
.onFailure().recoverWithUni(throwable -> {
210
System.err.println("Token refresh failed: " + throwable.getMessage());
211
// Fall back to getting new tokens
212
return obtainInitialTokens();
213
});
214
}
215
216
private Uni<String> refreshTokensProactively(Tokens currentTokens) {
217
String refreshToken = currentTokens.getRefreshToken();
218
219
if (refreshToken != null && !currentTokens.isRefreshTokenExpired()) {
220
return oidcClient.refreshTokens(refreshToken)
221
.onItem().invoke(tokens -> {
222
this.currentTokens.set(tokens);
223
logTokenInfo("Proactively refreshed tokens", tokens);
224
})
225
.map(Tokens::getAccessToken)
226
.onFailure().recoverWithItem(throwable -> {
227
System.err.println("Proactive refresh failed, using current token: " +
228
throwable.getMessage());
229
// Fall back to current token if proactive refresh fails
230
return currentTokens.getAccessToken();
231
});
232
} else {
233
// No refresh token available, use current access token
234
return Uni.createFrom().item(currentTokens.getAccessToken());
235
}
236
}
237
238
private void logTokenInfo(String action, Tokens tokens) {
239
Long expiresAt = tokens.getAccessTokenExpiresAt();
240
String expirationInfo = expiresAt != null ?
241
Instant.ofEpochSecond(expiresAt).toString() : "Never";
242
243
System.out.println(String.format(
244
"%s - Client: %s, Expires: %s, Has refresh: %s",
245
action,
246
tokens.getClientId(),
247
expirationInfo,
248
tokens.getRefreshToken() != null
249
));
250
}
251
252
/**
253
* Revoke current tokens and clear cache
254
*/
255
public Uni<Void> revokeAndClearTokens() {
256
Tokens tokens = currentTokens.getAndSet(null);
257
258
if (tokens != null) {
259
return oidcClient.revokeAccessToken(tokens.getAccessToken())
260
.onItem().invoke(revoked -> {
261
if (revoked) {
262
System.out.println("Tokens revoked and cleared");
263
} else {
264
System.out.println("Token revocation may need to be retried");
265
}
266
})
267
.onFailure().invoke(throwable ->
268
System.err.println("Failed to revoke tokens: " + throwable.getMessage())
269
)
270
.replaceWithVoid();
271
} else {
272
return Uni.createFrom().voidItem();
273
}
274
}
275
}
276
```
277
278
### Token Expiration Strategies
279
280
Different strategies for handling token expiration based on application requirements.
281
282
```java
283
/**
284
* Conservative strategy - refresh tokens well before expiration
285
*/
286
public boolean shouldRefreshConservative(Tokens tokens) {
287
if (tokens.isAccessTokenExpired()) {
288
return true; // Must refresh
289
}
290
291
Long expiresAt = tokens.getAccessTokenExpiresAt();
292
if (expiresAt != null) {
293
long now = Instant.now().getEpochSecond();
294
long timeToExpiry = expiresAt - now;
295
296
// Refresh if less than 5 minutes remaining
297
return timeToExpiry < 300;
298
}
299
300
return false;
301
}
302
303
/**
304
* Aggressive strategy - refresh tokens just before expiration
305
*/
306
public boolean shouldRefreshAggressive(Tokens tokens) {
307
if (tokens.isAccessTokenExpired()) {
308
return true; // Must refresh
309
}
310
311
Long expiresAt = tokens.getAccessTokenExpiresAt();
312
if (expiresAt != null) {
313
long now = Instant.now().getEpochSecond();
314
long timeToExpiry = expiresAt - now;
315
316
// Refresh if less than 30 seconds remaining
317
return timeToExpiry < 30;
318
}
319
320
return false;
321
}
322
323
/**
324
* Use built-in strategy with configured time skew
325
*/
326
public boolean shouldRefreshBuiltIn(Tokens tokens) {
327
return tokens.isAccessTokenWithinRefreshInterval();
328
}
329
```