or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

common-utilities.mddevice-flow.mderror-handling.mdindex.mdoauth1.mdoauth2-clients.mdoauth2-servers.mdopenid-connect.mdrequest-validation.mdtoken-management.md

token-management.mddocs/

0

# Token Management

1

2

Token creation, validation, and formatting with support for Bearer tokens, MAC tokens, and JWT tokens. Includes token generators, validators, and utility functions for comprehensive token lifecycle management.

3

4

## Capabilities

5

6

### OAuth 2.0 Token

7

8

OAuth 2.0 token object providing scope management, token metadata, and validation utilities. Extends Python dictionary with OAuth-specific functionality.

9

10

```python { .api }

11

class OAuth2Token(dict[str, str]):

12

def __init__(

13

self,

14

params: dict[str, str],

15

old_scope: str | list[str] | None = None,

16

): ...

17

18

@property

19

def scope_changed(self) -> bool:

20

"""Whether scope changed from original token."""

21

22

@property

23

def old_scope(self) -> str | None:

24

"""Original token scope as string."""

25

26

@property

27

def old_scopes(self) -> list[str]:

28

"""Original token scopes as list."""

29

30

@property

31

def scope(self) -> str | None:

32

"""Current token scope as string."""

33

34

@property

35

def scopes(self) -> list[str]:

36

"""Current token scopes as list."""

37

38

@property

39

def missing_scopes(self) -> list[str]:

40

"""Scopes that were removed from original."""

41

42

@property

43

def additional_scopes(self) -> list[str]:

44

"""Scopes that were added to original."""

45

```

46

47

### Bearer Token Handler

48

49

Bearer token implementation providing token creation, validation, and request processing according to RFC 6750.

50

51

```python { .api }

52

class BearerToken:

53

def __init__(

54

self,

55

request_validator=None,

56

token_generator=None,

57

expires_in: int | None = None,

58

refresh_token_generator=None,

59

):

60

"""

61

Bearer token handler.

62

63

Parameters:

64

- request_validator: Request validator instance

65

- token_generator: Function to generate access tokens

66

- expires_in: Token expiration time in seconds

67

- refresh_token_generator: Function to generate refresh tokens

68

"""

69

70

def create_token(

71

self,

72

request,

73

refresh_token: bool = False,

74

**kwargs,

75

) -> OAuth2Token:

76

"""

77

Create new bearer token.

78

79

Parameters:

80

- request: OAuth request object

81

- refresh_token: Whether to include refresh token

82

83

Returns:

84

OAuth2Token with access token and optional refresh token

85

"""

86

87

def validate_request(self, request) -> bool:

88

"""Validate bearer token request."""

89

90

def estimate_type(self, request) -> int:

91

"""Estimate confidence that request uses bearer tokens."""

92

```

93

94

### Token Utility Functions

95

96

Utility functions for token preparation, extraction, and formatting across different authentication methods.

97

98

```python { .api }

99

def prepare_bearer_uri(token: str, uri: str) -> str:

100

"""Add bearer token to URI query parameters."""

101

102

def prepare_bearer_headers(

103

token: str,

104

headers: dict[str, str] | None = None,

105

) -> dict[str, str]:

106

"""Add bearer token to Authorization header."""

107

108

def prepare_bearer_body(token: str, body: str = "") -> str:

109

"""Add bearer token to request body."""

110

111

def get_token_from_header(request) -> str | None:

112

"""Extract bearer token from Authorization header."""

113

114

def prepare_mac_header(

115

token: str,

116

uri: str,

117

key: str | bytes | bytearray,

118

http_method: str,

119

nonce: str | None = None,

120

headers: dict[str, str] | None = None,

121

body: str | None = None,

122

ext: str = "",

123

hash_algorithm: str = "hmac-sha-1",

124

issue_time: datetime | None = None,

125

draft: int = 0,

126

) -> dict[str, str]:

127

"""Prepare MAC authentication header."""

128

```

129

130

### Token Generators

131

132

Token generation functions for creating secure access tokens and refresh tokens.

133

134

```python { .api }

135

def random_token_generator(request, refresh_token: bool = False) -> str:

136

"""Generate random token using cryptographically secure methods."""

137

138

def signed_token_generator(private_pem: str, **kwargs) -> callable:

139

"""

140

Create signed token generator using RSA private key.

141

142

Parameters:

143

- private_pem: RSA private key in PEM format

144

145

Returns:

146

Function that generates signed JWT tokens

147

"""

148

```

149

150

## Usage Examples

151

152

### Bearer Token Usage

153

154

```python

155

from oauthlib.oauth2 import BearerToken, RequestValidator

156

157

class MyRequestValidator(RequestValidator):

158

def validate_bearer_token(self, token, scopes, request):

159

# Validate bearer token from database

160

token_data = get_token_from_db(token)

161

if not token_data or token_data.expired:

162

return False

163

164

# Check if token has required scopes

165

token_scopes = token_data.scopes.split()

166

return all(scope in token_scopes for scope in scopes)

167

168

def save_bearer_token(self, token, request, *args, **kwargs):

169

# Store bearer token in database

170

store_token_in_db(token, request.user_id, request.client_id)

171

172

# Create bearer token handler

173

validator = MyRequestValidator()

174

bearer_token = BearerToken(

175

request_validator=validator,

176

expires_in=3600, # 1 hour

177

)

178

179

# Create token for authorized request

180

token = bearer_token.create_token(request, refresh_token=True)

181

# Returns: {

182

# 'access_token': 'abc123...',

183

# 'token_type': 'Bearer',

184

# 'expires_in': 3600,

185

# 'refresh_token': 'def456...',

186

# 'scope': 'read write'

187

# }

188

```

189

190

### Custom Token Generator

191

192

```python

193

import jwt

194

from datetime import datetime, timedelta

195

from oauthlib.common import generate_token

196

197

def jwt_token_generator(request):

198

"""Generate JWT access tokens."""

199

payload = {

200

'sub': request.user_id,

201

'client_id': request.client_id,

202

'scopes': request.scopes,

203

'iat': datetime.utcnow(),

204

'exp': datetime.utcnow() + timedelta(hours=1),

205

'jti': generate_token(16) # JWT ID

206

}

207

return jwt.encode(payload, 'your-secret-key', algorithm='HS256')

208

209

# Use custom generator

210

bearer_token = BearerToken(

211

request_validator=validator,

212

token_generator=jwt_token_generator,

213

refresh_token_generator=lambda req: generate_token(32)

214

)

215

```

216

217

### Token Preparation for Requests

218

219

```python

220

from oauthlib.oauth2.rfc6749.tokens import (

221

prepare_bearer_headers,

222

prepare_bearer_uri,

223

prepare_bearer_body

224

)

225

226

access_token = 'abc123def456'

227

228

# Add token to Authorization header (recommended)

229

headers = prepare_bearer_headers(access_token)

230

# {'Authorization': 'Bearer abc123def456'}

231

232

# Add token to URI query (less secure)

233

uri = prepare_bearer_uri(access_token, 'https://api.example.com/data')

234

# 'https://api.example.com/data?access_token=abc123def456'

235

236

# Add token to request body (for POST requests)

237

body = prepare_bearer_body(access_token, 'data=value')

238

# 'data=value&access_token=abc123def456'

239

```

240

241

### Token Validation

242

243

```python

244

from oauthlib.oauth2.rfc6749.tokens import get_token_from_header

245

246

def validate_api_request(request):

247

"""Validate API request with bearer token."""

248

249

# Extract token from request

250

token = get_token_from_header(request)

251

if not token:

252

return False, "Missing access token"

253

254

# Validate token

255

token_data = get_token_from_database(token)

256

if not token_data:

257

return False, "Invalid access token"

258

259

if token_data.expired:

260

return False, "Access token expired"

261

262

# Check scopes for this endpoint

263

required_scopes = ['api:read']

264

token_scopes = token_data.scopes.split()

265

if not all(scope in token_scopes for scope in required_scopes):

266

return False, "Insufficient scope"

267

268

return True, token_data

269

```

270

271

### OAuth2Token Usage

272

273

```python

274

from oauthlib.oauth2.rfc6749.tokens import OAuth2Token

275

276

# Create token from server response

277

response_data = {

278

'access_token': 'abc123',

279

'token_type': 'Bearer',

280

'expires_in': 3600,

281

'refresh_token': 'def456',

282

'scope': 'read write admin'

283

}

284

285

token = OAuth2Token(response_data, old_scope='read write')

286

287

# Check scope changes

288

print(token.scope_changed) # True (admin scope added)

289

print(token.scopes) # ['read', 'write', 'admin']

290

print(token.old_scopes) # ['read', 'write']

291

print(token.additional_scopes) # ['admin']

292

print(token.missing_scopes) # []

293

294

# Token acts like a dictionary

295

print(token['access_token']) # 'abc123'

296

print(token.get('expires_in')) # 3600

297

```

298

299

### MAC Token Authentication

300

301

```python

302

from oauthlib.oauth2.rfc6749.tokens import prepare_mac_header

303

import datetime

304

305

# Prepare MAC authentication header

306

mac_header = prepare_mac_header(

307

token='h480djs93hd8',

308

uri='https://api.example.com/data',

309

key='secret-mac-key',

310

http_method='GET',

311

nonce='unique-nonce-123',

312

hash_algorithm='hmac-sha-256',

313

issue_time=datetime.datetime.utcnow()

314

)

315

316

print(mac_header)

317

# {

318

# 'Authorization': 'MAC id="h480djs93hd8", nonce="unique-nonce-123",

319

# ts="1234567890", mac="signature..."'

320

# }

321

```

322

323

## Token Lifecycle Management

324

325

### Token Refresh Flow

326

327

```python

328

def refresh_access_token(refresh_token, client_id, client_secret):

329

"""Refresh an expired access token."""

330

from oauthlib.oauth2 import WebApplicationClient

331

import requests

332

333

client = WebApplicationClient(client_id)

334

335

# Prepare refresh request

336

token_url, headers, body = client.prepare_refresh_token_request(

337

'https://auth.example.com/token',

338

refresh_token=refresh_token,

339

scope=['read', 'write'] # Optional: request different scopes

340

)

341

342

# Add client authentication

343

headers['Authorization'] = f'Basic {base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()}'

344

345

# Make request

346

response = requests.post(token_url, headers=headers, data=body)

347

348

if response.status_code == 200:

349

return client.parse_request_body_response(response.text)

350

else:

351

raise Exception(f"Token refresh failed: {response.text}")

352

```

353

354

### Token Revocation

355

356

```python

357

def revoke_token(token, token_type_hint, client_id, client_secret):

358

"""Revoke an access or refresh token."""

359

from oauthlib.oauth2 import WebApplicationClient

360

import requests

361

362

client = WebApplicationClient(client_id)

363

364

# Prepare revocation request

365

revoke_url, headers, body = client.prepare_token_revocation_request(

366

'https://auth.example.com/revoke',

367

token=token,

368

token_type_hint=token_type_hint # 'access_token' or 'refresh_token'

369

)

370

371

# Add client authentication

372

headers['Authorization'] = f'Basic {base64.b64encode(f"{client_id}:{client_secret}".encode()).decode()}'

373

374

# Make request

375

response = requests.post(revoke_url, headers=headers, data=body)

376

377

return response.status_code == 200

378

```