or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-security.mdauthorization-flows.mdclient-authentication.mdconfiguration.mdgrant-types.mdindex.mdpassport-integration.mdprotected-resources.mdtoken-management.md

token-management.mddocs/

0

# Token Management

1

2

Token introspection, revocation, and lifecycle management operations for OAuth 2.0 access and refresh tokens.

3

4

## Capabilities

5

6

### Token Introspection

7

8

Query token status and metadata using RFC 7662 token introspection.

9

10

```typescript { .api }

11

/**

12

* Introspect token status and metadata

13

* @param config - Configuration instance

14

* @param token - Token to introspect (access or refresh token)

15

* @param parameters - Additional introspection parameters

16

* @returns Promise resolving to introspection response

17

*/

18

function tokenIntrospection(

19

config: Configuration,

20

token: string,

21

parameters?: URLSearchParams | Record<string, string>

22

): Promise<IntrospectionResponse>;

23

```

24

25

**Usage Examples:**

26

27

```typescript

28

import * as client from "openid-client";

29

30

// Basic token introspection

31

const introspection = await client.tokenIntrospection(config, accessToken);

32

33

if (introspection.active) {

34

console.log("Token is active");

35

console.log("Scope:", introspection.scope);

36

console.log("Client ID:", introspection.client_id);

37

console.log("Username:", introspection.username);

38

console.log("Expires at:", new Date(introspection.exp * 1000));

39

} else {

40

console.log("Token is inactive");

41

}

42

43

// With token type hint for better performance

44

const introspection = await client.tokenIntrospection(

45

config,

46

accessToken,

47

{

48

token_type_hint: "access_token"

49

}

50

);

51

52

// Introspect refresh token

53

const refreshIntrospection = await client.tokenIntrospection(

54

config,

55

refreshToken,

56

{

57

token_type_hint: "refresh_token"

58

}

59

);

60

61

// Check specific token properties

62

if (introspection.active) {

63

// Check if token has required scope

64

const hasScope = introspection.scope?.includes("read:users");

65

66

// Check token expiration

67

const expiresIn = introspection.exp - Math.floor(Date.now() / 1000);

68

if (expiresIn < 300) {

69

console.log("Token expires in less than 5 minutes");

70

}

71

72

// Check audience

73

if (Array.isArray(introspection.aud)) {

74

console.log("Token audiences:", introspection.aud);

75

} else if (introspection.aud) {

76

console.log("Token audience:", introspection.aud);

77

}

78

}

79

```

80

81

### Token Revocation

82

83

Revoke access or refresh tokens using RFC 7009 token revocation.

84

85

```typescript { .api }

86

/**

87

* Revoke token

88

* @param config - Configuration instance

89

* @param token - Token to revoke (access or refresh token)

90

* @param parameters - Additional revocation parameters

91

* @returns Promise resolving when revocation is complete

92

*/

93

function tokenRevocation(

94

config: Configuration,

95

token: string,

96

parameters?: URLSearchParams | Record<string, string>

97

): Promise<void>;

98

```

99

100

**Usage Examples:**

101

102

```typescript

103

import * as client from "openid-client";

104

105

// Basic token revocation

106

await client.tokenRevocation(config, accessToken);

107

console.log("Access token revoked");

108

109

// With token type hint

110

await client.tokenRevocation(config, refreshToken, {

111

token_type_hint: "refresh_token"

112

});

113

console.log("Refresh token revoked");

114

115

// Revoke all tokens (if supported by server)

116

// Revoking refresh token may invalidate associated access tokens

117

await client.tokenRevocation(config, refreshToken, {

118

token_type_hint: "refresh_token"

119

});

120

121

// Error handling

122

try {

123

await client.tokenRevocation(config, token);

124

} catch (error) {

125

if (error.error === "unsupported_token_type") {

126

console.log("Server doesn't support revoking this token type");

127

} else if (error.error === "invalid_request") {

128

console.log("Invalid revocation request");

129

} else {

130

console.log("Revocation failed:", error.message);

131

}

132

}

133

```

134

135

## Token Lifecycle Management

136

137

Complete token lifecycle management patterns:

138

139

**Token Storage and Refresh:**

140

141

```typescript

142

import * as client from "openid-client";

143

144

interface TokenStorage {

145

accessToken?: string;

146

refreshToken?: string;

147

expiresAt?: number;

148

idToken?: string;

149

}

150

151

class TokenManager {

152

private tokens: TokenStorage = {};

153

154

constructor(private config: client.Configuration) {}

155

156

async getValidAccessToken(): Promise<string> {

157

// Check if current token is valid

158

if (this.tokens.accessToken && this.tokens.expiresAt) {

159

const now = Math.floor(Date.now() / 1000);

160

const bufferTime = 300; // 5 minutes buffer

161

162

if (this.tokens.expiresAt > now + bufferTime) {

163

return this.tokens.accessToken;

164

}

165

}

166

167

// Refresh if needed

168

if (this.tokens.refreshToken) {

169

await this.refreshTokens();

170

return this.tokens.accessToken!;

171

}

172

173

throw new Error("No valid tokens available");

174

}

175

176

async refreshTokens(): Promise<void> {

177

if (!this.tokens.refreshToken) {

178

throw new Error("No refresh token available");

179

}

180

181

try {

182

const newTokens = await client.refreshTokenGrant(

183

this.config,

184

this.tokens.refreshToken

185

);

186

187

this.storeTokens(newTokens);

188

} catch (error) {

189

// Refresh failed - tokens may be expired

190

this.clearTokens();

191

throw error;

192

}

193

}

194

195

storeTokens(tokens: client.TokenEndpointResponse & client.TokenEndpointResponseHelpers): void {

196

this.tokens.accessToken = tokens.access_token;

197

this.tokens.refreshToken = tokens.refresh_token || this.tokens.refreshToken;

198

this.tokens.idToken = tokens.id_token;

199

200

if (tokens.expires_in) {

201

this.tokens.expiresAt = Math.floor(Date.now() / 1000) + tokens.expires_in;

202

}

203

}

204

205

async revokeTokens(): Promise<void> {

206

const promises: Promise<void>[] = [];

207

208

if (this.tokens.accessToken) {

209

promises.push(

210

client.tokenRevocation(this.config, this.tokens.accessToken, {

211

token_type_hint: "access_token"

212

})

213

);

214

}

215

216

if (this.tokens.refreshToken) {

217

promises.push(

218

client.tokenRevocation(this.config, this.tokens.refreshToken, {

219

token_type_hint: "refresh_token"

220

})

221

);

222

}

223

224

await Promise.allSettled(promises);

225

this.clearTokens();

226

}

227

228

clearTokens(): void {

229

this.tokens = {};

230

}

231

232

async introspectToken(token?: string): Promise<client.IntrospectionResponse> {

233

const tokenToIntrospect = token || this.tokens.accessToken;

234

if (!tokenToIntrospect) {

235

throw new Error("No token to introspect");

236

}

237

238

return client.tokenIntrospection(this.config, tokenToIntrospect);

239

}

240

}

241

```

242

243

## Response Types

244

245

```typescript { .api }

246

interface IntrospectionResponse {

247

/** Whether the token is currently active */

248

active: boolean;

249

250

/** Space-separated list of scopes */

251

scope?: string;

252

253

/** Client identifier */

254

client_id?: string;

255

256

/** Username of the resource owner */

257

username?: string;

258

259

/** Token type (usually "Bearer") */

260

token_type?: string;

261

262

/** Token expiration time (seconds since epoch) */

263

exp?: number;

264

265

/** Token issued at time (seconds since epoch) */

266

iat?: number;

267

268

/** Token not before time (seconds since epoch) */

269

nbf?: number;

270

271

/** Subject identifier */

272

sub?: string;

273

274

/** Intended audience */

275

aud?: string | string[];

276

277

/** Issuer identifier */

278

iss?: string;

279

280

/** JWT ID */

281

jti?: string;

282

283

// Additional server-specific claims may be present

284

[key: string]: any;

285

}

286

```

287

288

## Error Handling

289

290

Common error scenarios and handling:

291

292

```typescript

293

import * as client from "openid-client";

294

295

// Introspection error handling

296

try {

297

const result = await client.tokenIntrospection(config, token);

298

} catch (error) {

299

if (error.error === "invalid_request") {

300

console.log("Invalid introspection request");

301

} else if (error.error === "invalid_token") {

302

console.log("Token is invalid or malformed");

303

} else if (error.error === "unsupported_token_type") {

304

console.log("Server doesn't support introspecting this token type");

305

}

306

}

307

308

// Revocation error handling

309

try {

310

await client.tokenRevocation(config, token);

311

} catch (error) {

312

if (error.error === "invalid_request") {

313

console.log("Invalid revocation request");

314

} else if (error.error === "invalid_token") {

315

console.log("Token is invalid or already revoked");

316

} else if (error.error === "unsupported_token_type") {

317

console.log("Server doesn't support revoking this token type");

318

}

319

320

// Note: Some servers return success even for invalid tokens

321

// Check server documentation for specific behavior

322

}

323

```

324

325

## Server Capability Detection

326

327

Check server support for token management operations:

328

329

```typescript

330

import * as client from "openid-client";

331

332

// Check server metadata for supported operations

333

const serverMetadata = config.serverMetadata();

334

335

// Check for introspection support

336

if (serverMetadata.introspection_endpoint) {

337

console.log("Server supports token introspection");

338

339

// Check supported authentication methods for introspection

340

if (serverMetadata.introspection_endpoint_auth_methods_supported) {

341

console.log("Supported auth methods:",

342

serverMetadata.introspection_endpoint_auth_methods_supported);

343

}

344

}

345

346

// Check for revocation support

347

if (serverMetadata.revocation_endpoint) {

348

console.log("Server supports token revocation");

349

350

// Check supported authentication methods for revocation

351

if (serverMetadata.revocation_endpoint_auth_methods_supported) {

352

console.log("Supported auth methods:",

353

serverMetadata.revocation_endpoint_auth_methods_supported);

354

}

355

}

356

```