or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

access-token.mdauthorization-code.mdclient-credentials.mdindex.mdresource-owner-password.md

access-token.mddocs/

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

```