0
# Access Token Management
1
2
The AccessToken class provides comprehensive token lifecycle management for OAuth 2.0 access tokens, including expiration checking, token refresh, and revocation capabilities. All grant type classes return AccessToken instances that offer these management features.
3
4
## Overview
5
6
AccessToken instances are returned by all grant type methods (`getToken()` and `createToken()`) and provide a consistent interface for managing token lifecycles across different OAuth 2.0 flows. The class handles token expiration calculation, refresh operations, and revocation requests.
7
8
## Core Usage
9
10
AccessToken instances are created by grant type classes - you don't typically instantiate them directly:
11
12
```javascript
13
const { AuthorizationCode } = require('simple-oauth2');
14
15
const client = new AuthorizationCode(config);
16
const accessToken = await client.getToken(params); // Returns AccessToken instance
17
```
18
19
## AccessToken Class
20
21
### Properties
22
23
```typescript { .api }
24
readonly token: TokenObject
25
```
26
27
Immutable object containing the token data. This property contains the raw token response from the authorization server, plus any computed properties like `expires_at`.
28
29
**Example:**
30
```javascript
31
const accessToken = await client.getToken(params);
32
33
console.log(accessToken.token);
34
// {
35
// access_token: "eyJhbGciOiJIUzI1...",
36
// refresh_token: "def50200ef12...",
37
// token_type: "Bearer",
38
// expires_in: 3600,
39
// expires_at: 2023-12-01T10:30:00.000Z,
40
// scope: "read write"
41
// }
42
```
43
44
### Check Token Expiration
45
46
```typescript { .api }
47
expired(expirationWindowSeconds?: number): boolean
48
```
49
50
Determines if the access token has expired or is about to expire within a specified window.
51
52
**Parameters:**
53
- `expirationWindowSeconds` (number, optional) - Time window before actual expiration to consider token expired. Defaults to 0.
54
55
**Returns:** Boolean indicating whether the token is expired or about to expire
56
57
**Example:**
58
```javascript
59
const accessToken = await client.getToken(params);
60
61
// Check if token is currently expired
62
if (accessToken.expired()) {
63
console.log('Token has expired');
64
}
65
66
// Check if token expires within 5 minutes (300 seconds)
67
if (accessToken.expired(300)) {
68
console.log('Token expires soon, should refresh');
69
const refreshedToken = await accessToken.refresh();
70
}
71
72
// Use in a token validation function
73
function isTokenValid(token, bufferSeconds = 60) {
74
return !token.expired(bufferSeconds);
75
}
76
```
77
78
### Refresh Access Token
79
80
```typescript { .api }
81
refresh(params?: RefreshParams, httpOptions?: any): Promise<AccessToken>
82
```
83
84
Refreshes the access token using the refresh token. Returns a new AccessToken instance.
85
86
**Parameters:**
87
- `params.scope` (string | string[], optional) - Subset of original scopes to request
88
- Additional parameters are automatically serialized for the refresh request
89
- `httpOptions` (object, optional) - HTTP options passed to underlying request library
90
91
**Returns:** Promise resolving to new AccessToken instance
92
93
**Example:**
94
```javascript
95
// Basic token refresh
96
const refreshedToken = await accessToken.refresh();
97
98
// Refresh with reduced scope
99
const refreshedToken = await accessToken.refresh({
100
scope: ['read'] // Request only read scope
101
});
102
103
// Refresh with custom HTTP options
104
const refreshedToken = await accessToken.refresh({}, {
105
timeout: 10000,
106
headers: {
107
'User-Agent': 'MyApp/1.0'
108
}
109
});
110
111
console.log('New access token:', refreshedToken.token.access_token);
112
```
113
114
### Revoke Specific Token
115
116
```typescript { .api }
117
revoke(tokenType: 'access_token' | 'refresh_token', httpOptions?: any): Promise<void>
118
```
119
120
Revokes either the access token or refresh token.
121
122
**Parameters:**
123
- `tokenType` ('access_token' | 'refresh_token') - Type of token to revoke
124
- `httpOptions` (object, optional) - HTTP options passed to underlying request library
125
126
**Returns:** Promise that resolves when revocation is complete
127
128
**Example:**
129
```javascript
130
// Revoke access token only
131
await accessToken.revoke('access_token');
132
133
// Revoke refresh token only
134
await accessToken.revoke('refresh_token');
135
136
// Revoke with custom HTTP options
137
await accessToken.revoke('access_token', {
138
timeout: 5000
139
});
140
```
141
142
### Revoke All Tokens
143
144
```typescript { .api }
145
revokeAll(httpOptions?: any): Promise<void>
146
```
147
148
Revokes both the access token and refresh token.
149
150
**Parameters:**
151
- `httpOptions` (object, optional) - HTTP options passed to underlying request library
152
153
**Returns:** Promise that resolves when both tokens are revoked
154
155
**Example:**
156
```javascript
157
// Revoke both tokens (logout)
158
await accessToken.revokeAll();
159
160
// Revoke with custom HTTP options
161
await accessToken.revokeAll({
162
timeout: 10000
163
});
164
```
165
166
### Get Token JSON
167
168
```typescript { .api }
169
toJSON(): TokenObject
170
```
171
172
Returns the token's internal JSON representation for serialization.
173
174
**Returns:** Token object that can be stored or transmitted
175
176
**Example:**
177
```javascript
178
// Store token in database
179
const tokenData = accessToken.toJSON();
180
await database.saveToken(userId, tokenData);
181
182
// Store token in local storage (browser)
183
localStorage.setItem('oauth_token', JSON.stringify(accessToken.toJSON()));
184
185
// Recreate token from stored data
186
const storedToken = JSON.parse(localStorage.getItem('oauth_token'));
187
const recreatedToken = client.createToken(storedToken);
188
```
189
190
## Type Definitions
191
192
```typescript { .api }
193
interface TokenObject {
194
access_token: string;
195
refresh_token?: string;
196
token_type?: string;
197
expires_in?: number;
198
expires_at?: Date;
199
scope?: string;
200
[key: string]: any;
201
}
202
203
interface RefreshParams {
204
scope?: string | string[];
205
[key: string]: any;
206
}
207
```
208
209
## Common Usage Patterns
210
211
### Automatic Token Refresh
212
213
```javascript
214
class TokenManager {
215
constructor(grantClient) {
216
this.client = grantClient;
217
this.currentToken = null;
218
}
219
220
async getValidToken() {
221
// First time or no cached token
222
if (!this.currentToken) {
223
throw new Error('No token available. Authenticate first.');
224
}
225
226
// Check if token needs refresh (5 minute buffer)
227
if (this.currentToken.expired(300)) {
228
console.log('Token expired, refreshing...');
229
this.currentToken = await this.currentToken.refresh();
230
}
231
232
return this.currentToken;
233
}
234
235
async setToken(token) {
236
this.currentToken = token;
237
}
238
239
async makeAuthenticatedRequest(url, options = {}) {
240
const token = await this.getValidToken();
241
242
return fetch(url, {
243
...options,
244
headers: {
245
...options.headers,
246
'Authorization': `Bearer ${token.token.access_token}`
247
}
248
});
249
}
250
}
251
252
// Usage
253
const tokenManager = new TokenManager(oauthClient);
254
255
// Initial authentication
256
const initialToken = await oauthClient.getToken(params);
257
await tokenManager.setToken(initialToken);
258
259
// Make requests (token will auto-refresh if needed)
260
const response = await tokenManager.makeAuthenticatedRequest('https://api.example.com/data');
261
```
262
263
### Token Persistence with Refresh
264
265
```javascript
266
class PersistentTokenManager {
267
constructor(grantClient, storage) {
268
this.client = grantClient;
269
this.storage = storage;
270
}
271
272
async loadToken() {
273
const tokenData = await this.storage.getItem('oauth_token');
274
if (!tokenData) return null;
275
276
try {
277
const token = this.client.createToken(JSON.parse(tokenData));
278
279
// Refresh if expired
280
if (token.expired()) {
281
const refreshedToken = await token.refresh();
282
await this.saveToken(refreshedToken);
283
return refreshedToken;
284
}
285
286
return token;
287
} catch (error) {
288
console.error('Failed to load/refresh token:', error);
289
await this.storage.removeItem('oauth_token');
290
return null;
291
}
292
}
293
294
async saveToken(token) {
295
await this.storage.setItem('oauth_token', JSON.stringify(token.toJSON()));
296
}
297
298
async clearToken() {
299
await this.storage.removeItem('oauth_token');
300
}
301
302
async logout(token) {
303
try {
304
// Revoke tokens on server
305
await token.revokeAll();
306
} catch (error) {
307
console.warn('Failed to revoke tokens:', error);
308
} finally {
309
// Clear local storage regardless
310
await this.clearToken();
311
}
312
}
313
}
314
315
// Usage with localStorage
316
const tokenManager = new PersistentTokenManager(oauthClient, {
317
getItem: (key) => Promise.resolve(localStorage.getItem(key)),
318
setItem: (key, value) => Promise.resolve(localStorage.setItem(key, value)),
319
removeItem: (key) => Promise.resolve(localStorage.removeItem(key))
320
});
321
322
// Load existing token on app start
323
const existingToken = await tokenManager.loadToken();
324
if (existingToken) {
325
console.log('Loaded existing token');
326
} else {
327
console.log('No valid token found, need to authenticate');
328
}
329
```
330
331
### Token Expiration Monitoring
332
333
```javascript
334
class TokenExpirationMonitor {
335
constructor(token, onExpiry, checkInterval = 60000) {
336
this.token = token;
337
this.onExpiry = onExpiry;
338
this.checkInterval = checkInterval;
339
this.intervalId = null;
340
}
341
342
start() {
343
this.intervalId = setInterval(() => {
344
// Check if token expires within 5 minutes
345
if (this.token.expired(300)) {
346
this.stop();
347
this.onExpiry(this.token);
348
}
349
}, this.checkInterval);
350
}
351
352
stop() {
353
if (this.intervalId) {
354
clearInterval(this.intervalId);
355
this.intervalId = null;
356
}
357
}
358
359
updateToken(newToken) {
360
this.token = newToken;
361
}
362
}
363
364
// Usage
365
const monitor = new TokenExpirationMonitor(
366
accessToken,
367
async (expiredToken) => {
368
console.log('Token is expiring, attempting refresh...');
369
try {
370
const refreshedToken = await expiredToken.refresh();
371
monitor.updateToken(refreshedToken);
372
monitor.start(); // Restart monitoring
373
console.log('Token refreshed successfully');
374
} catch (error) {
375
console.error('Failed to refresh token:', error);
376
// Handle re-authentication
377
}
378
}
379
);
380
381
monitor.start();
382
```
383
384
### Secure Token Storage
385
386
```javascript
387
// Example using Node.js with encrypted storage
388
const crypto = require('crypto');
389
390
class SecureTokenStorage {
391
constructor(encryptionKey) {
392
this.algorithm = 'aes-256-gcm';
393
this.key = crypto.scryptSync(encryptionKey, 'salt', 32);
394
}
395
396
encrypt(text) {
397
const iv = crypto.randomBytes(16);
398
const cipher = crypto.createCipher(this.algorithm, this.key);
399
cipher.setAAD(Buffer.from('oauth-token'));
400
401
let encrypted = cipher.update(text, 'utf8', 'hex');
402
encrypted += cipher.final('hex');
403
404
const authTag = cipher.getAuthTag();
405
406
return {
407
encrypted,
408
iv: iv.toString('hex'),
409
authTag: authTag.toString('hex')
410
};
411
}
412
413
decrypt(encryptedData) {
414
const decipher = crypto.createDecipher(this.algorithm, this.key);
415
decipher.setAAD(Buffer.from('oauth-token'));
416
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
417
418
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
419
decrypted += decipher.final('utf8');
420
421
return decrypted;
422
}
423
424
async saveToken(token) {
425
const tokenJson = JSON.stringify(token.toJSON());
426
const encrypted = this.encrypt(tokenJson);
427
await fs.writeFile('token.enc', JSON.stringify(encrypted));
428
}
429
430
async loadToken(grantClient) {
431
try {
432
const encryptedData = JSON.parse(await fs.readFile('token.enc', 'utf8'));
433
const tokenJson = this.decrypt(encryptedData);
434
const tokenData = JSON.parse(tokenJson);
435
return grantClient.createToken(tokenData);
436
} catch (error) {
437
return null;
438
}
439
}
440
}
441
442
// Usage
443
const secureStorage = new SecureTokenStorage(process.env.ENCRYPTION_KEY);
444
445
// Save token securely
446
await secureStorage.saveToken(accessToken);
447
448
// Load token securely
449
const loadedToken = await secureStorage.loadToken(oauthClient);
450
```