0
# Grant Types
1
2
Complete implementation of OAuth 2.0 and OpenID Connect grant types including Client Credentials, Refresh Token, Device Authorization, Client-Initiated Backchannel Authentication (CIBA), and generic grant support.
3
4
## Capabilities
5
6
### Client Credentials Grant
7
8
Obtain access tokens using client credentials for machine-to-machine authentication.
9
10
```typescript { .api }
11
/**
12
* Execute Client Credentials Grant
13
* @param config - Configuration instance
14
* @param parameters - Additional parameters (scope, resource, etc.)
15
* @param options - Grant options (DPoP, etc.)
16
* @returns Promise resolving to token response with helpers
17
*/
18
function clientCredentialsGrant(
19
config: Configuration,
20
parameters?: URLSearchParams | Record<string, string>,
21
options?: DPoPOptions
22
): Promise<TokenEndpointResponse & TokenEndpointResponseHelpers>;
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import * as client from "openid-client";
29
30
// Basic client credentials grant
31
const tokens = await client.clientCredentialsGrant(config);
32
33
// With scope and resource parameters
34
const tokens = await client.clientCredentialsGrant(config, {
35
scope: "read:users write:users",
36
resource: "https://api.example.com"
37
});
38
39
// With multiple resources (resource indicators)
40
const tokens = await client.clientCredentialsGrant(config, {
41
scope: "api:access",
42
resource: ["https://api1.example.com", "https://api2.example.com"]
43
});
44
45
console.log("Access Token:", tokens.access_token);
46
console.log("Token Type:", tokens.token_type);
47
console.log("Expires In:", tokens.expiresIn(), "seconds");
48
```
49
50
### Refresh Token Grant
51
52
Exchange refresh tokens for new access tokens.
53
54
```typescript { .api }
55
/**
56
* Execute Refresh Token Grant
57
* @param config - Configuration instance
58
* @param refreshToken - Refresh token to exchange
59
* @param parameters - Additional parameters (scope, resource, etc.)
60
* @param options - Grant options (DPoP, etc.)
61
* @returns Promise resolving to token response with helpers
62
*/
63
function refreshTokenGrant(
64
config: Configuration,
65
refreshToken: string,
66
parameters?: URLSearchParams | Record<string, string>,
67
options?: DPoPOptions
68
): Promise<TokenEndpointResponse & TokenEndpointResponseHelpers>;
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
import * as client from "openid-client";
75
76
// Basic refresh token grant
77
const newTokens = await client.refreshTokenGrant(
78
config,
79
existingTokens.refresh_token
80
);
81
82
// With scope parameter (potentially reducing scope)
83
const newTokens = await client.refreshTokenGrant(
84
config,
85
existingTokens.refresh_token,
86
{
87
scope: "read:profile" // reduced from original scope
88
}
89
);
90
91
// With resource indicators
92
const newTokens = await client.refreshTokenGrant(
93
config,
94
existingTokens.refresh_token,
95
{
96
resource: "https://api.example.com",
97
scope: "api:read api:write"
98
}
99
);
100
101
// Check if refresh token was rotated
102
if (newTokens.refresh_token && newTokens.refresh_token !== existingTokens.refresh_token) {
103
console.log("Refresh token was rotated");
104
// Store new refresh token
105
}
106
```
107
108
### Device Authorization Grant
109
110
Implement device flow for input-constrained devices.
111
112
```typescript { .api }
113
/**
114
* Initiate Device Authorization Grant
115
* @param config - Configuration instance
116
* @param parameters - Authorization request parameters
117
* @returns Promise resolving to device authorization response
118
*/
119
function initiateDeviceAuthorization(
120
config: Configuration,
121
parameters: URLSearchParams | Record<string, string>
122
): Promise<DeviceAuthorizationResponse>;
123
124
/**
125
* Poll for Device Authorization Grant completion
126
* @param config - Configuration instance
127
* @param deviceAuthorizationResponse - Response from initiateDeviceAuthorization
128
* @param parameters - Additional token endpoint parameters
129
* @param options - Polling options
130
* @returns Promise resolving to token response when authorized
131
*/
132
function pollDeviceAuthorizationGrant(
133
config: Configuration,
134
deviceAuthorizationResponse: DeviceAuthorizationResponse,
135
parameters?: URLSearchParams | Record<string, string>,
136
options?: DeviceAuthorizationGrantPollOptions
137
): Promise<TokenEndpointResponse & TokenEndpointResponseHelpers>;
138
```
139
140
**Usage Examples:**
141
142
```typescript
143
import * as client from "openid-client";
144
145
// Initiate device flow
146
const deviceResponse = await client.initiateDeviceAuthorization(config, {
147
scope: "openid profile email"
148
});
149
150
// Display user instructions
151
console.log("Go to:", deviceResponse.verification_uri);
152
console.log("Enter code:", deviceResponse.user_code);
153
154
// Or use complete URI if available
155
if (deviceResponse.verification_uri_complete) {
156
console.log("Or visit:", deviceResponse.verification_uri_complete);
157
}
158
159
// Poll for completion
160
try {
161
const tokens = await client.pollDeviceAuthorizationGrant(
162
config,
163
deviceResponse
164
);
165
166
console.log("Device authorized!");
167
console.log("Access Token:", tokens.access_token);
168
console.log("ID Token Claims:", tokens.claims());
169
} catch (error) {
170
if (error.error === "access_denied") {
171
console.log("User denied the request");
172
} else if (error.error === "expired_token") {
173
console.log("Device code expired");
174
}
175
}
176
177
// Poll with timeout and additional parameters
178
const tokens = await client.pollDeviceAuthorizationGrant(
179
config,
180
deviceResponse,
181
{ resource: "https://api.example.com" }, // additional parameters
182
{
183
signal: AbortSignal.timeout(300000) // 5 minute timeout
184
}
185
);
186
```
187
188
### Client-Initiated Backchannel Authentication (CIBA)
189
190
Implement CIBA flow for authentication without user interaction on the requesting device.
191
192
```typescript { .api }
193
/**
194
* Initiate CIBA flow
195
* @param config - Configuration instance
196
* @param parameters - CIBA request parameters (must include one of login_hint, id_token_hint, or login_hint_token)
197
* @returns Promise resolving to backchannel authentication response
198
*/
199
function initiateBackchannelAuthentication(
200
config: Configuration,
201
parameters: URLSearchParams | Record<string, string>
202
): Promise<BackchannelAuthenticationResponse>;
203
204
/**
205
* Poll for CIBA completion
206
* @param config - Configuration instance
207
* @param backchannelAuthenticationResponse - Response from initiateBackchannelAuthentication
208
* @param parameters - Additional token endpoint parameters
209
* @param options - Polling options
210
* @returns Promise resolving to token response when authenticated
211
*/
212
function pollBackchannelAuthenticationGrant(
213
config: Configuration,
214
backchannelAuthenticationResponse: BackchannelAuthenticationResponse,
215
parameters?: URLSearchParams | Record<string, string>,
216
options?: BackchannelAuthenticationGrantPollOptions
217
): Promise<TokenEndpointResponse & TokenEndpointResponseHelpers>;
218
```
219
220
**Usage Examples:**
221
222
```typescript
223
import * as client from "openid-client";
224
225
// Initiate CIBA with login hint
226
const cibaResponse = await client.initiateBackchannelAuthentication(config, {
227
scope: "openid profile email",
228
login_hint: "user@example.com",
229
binding_message: "Please confirm transaction #12345"
230
});
231
232
console.log("Authentication initiated. Auth req ID:", cibaResponse.auth_req_id);
233
234
// Poll for completion (for poll mode)
235
try {
236
const tokens = await client.pollBackchannelAuthenticationGrant(
237
config,
238
cibaResponse
239
);
240
241
console.log("User authenticated!");
242
console.log("Access Token:", tokens.access_token);
243
console.log("ID Token Claims:", tokens.claims());
244
} catch (error) {
245
if (error.error === "access_denied") {
246
console.log("User denied authentication");
247
} else if (error.error === "expired_token") {
248
console.log("Authentication request expired");
249
}
250
}
251
252
// With ID token hint instead of login hint
253
const cibaResponse = await client.initiateBackchannelAuthentication(config, {
254
scope: "openid profile",
255
id_token_hint: previousIdToken,
256
user_code: "USER123" // optional user code for verification
257
});
258
```
259
260
### Generic Grant Request
261
262
Execute any OAuth 2.0 grant type including custom grants.
263
264
```typescript { .api }
265
/**
266
* Execute generic grant request
267
* @param config - Configuration instance
268
* @param grantType - Grant type identifier
269
* @param parameters - Grant-specific parameters
270
* @param options - Grant options (DPoP, etc.)
271
* @returns Promise resolving to token response with helpers
272
*/
273
function genericGrantRequest(
274
config: Configuration,
275
grantType: string,
276
parameters: URLSearchParams | Record<string, string>,
277
options?: DPoPOptions
278
): Promise<TokenEndpointResponse & TokenEndpointResponseHelpers>;
279
```
280
281
**Usage Examples:**
282
283
```typescript
284
import * as client from "openid-client";
285
286
// JWT Bearer Token Grant (RFC 7523)
287
const tokens = await client.genericGrantRequest(
288
config,
289
"urn:ietf:params:oauth:grant-type:jwt-bearer",
290
{
291
assertion: jwtAssertion,
292
scope: "api:access",
293
resource: "https://api.example.com"
294
}
295
);
296
297
// SAML 2.0 Bearer Assertion Grant (RFC 7522)
298
const tokens = await client.genericGrantRequest(
299
config,
300
"urn:ietf:params:oauth:grant-type:saml2-bearer",
301
{
302
assertion: samlAssertion,
303
scope: "read write"
304
}
305
);
306
307
// Token Exchange Grant (RFC 8693)
308
const tokens = await client.genericGrantRequest(
309
config,
310
"urn:ietf:params:oauth:grant-type:token-exchange",
311
{
312
subject_token: accessToken,
313
subject_token_type: "urn:ietf:params:oauth:token-type:access_token",
314
resource: "https://api.example.com",
315
audience: "https://api.example.com"
316
}
317
);
318
319
// Custom grant type
320
const tokens = await client.genericGrantRequest(
321
config,
322
"urn:example:custom-grant",
323
{
324
custom_parameter: "value",
325
scope: "custom:access"
326
}
327
);
328
```
329
330
## Grant Response Types
331
332
```typescript { .api }
333
interface DeviceAuthorizationResponse {
334
device_code: string;
335
user_code: string;
336
verification_uri: string;
337
verification_uri_complete?: string;
338
expires_in: number;
339
interval?: number;
340
}
341
342
interface BackchannelAuthenticationResponse {
343
auth_req_id: string;
344
expires_in: number;
345
interval?: number;
346
}
347
348
interface DeviceAuthorizationGrantPollOptions extends DPoPOptions {
349
/** AbortSignal to stop polling */
350
signal?: AbortSignal;
351
}
352
353
interface BackchannelAuthenticationGrantPollOptions extends DPoPOptions {
354
/** AbortSignal to stop polling */
355
signal?: AbortSignal;
356
}
357
```
358
359
## Token Response Helpers
360
361
```typescript { .api }
362
interface TokenEndpointResponse {
363
access_token: string;
364
token_type: string;
365
expires_in?: number;
366
refresh_token?: string;
367
scope?: string;
368
id_token?: string;
369
// Additional server-specific properties may be present
370
}
371
372
interface TokenEndpointResponseHelpers {
373
/**
374
* Parse ID Token claims (if present)
375
* @returns ID Token claims or undefined
376
*/
377
claims(): IDToken | undefined;
378
379
/**
380
* Calculate seconds until token expiration
381
* @returns Seconds until expiration or undefined
382
*/
383
expiresIn(): number | undefined;
384
}
385
```
386
387
## DPoP Support
388
389
All grant types support DPoP (Demonstrating Proof-of-Possession) for sender-constrained tokens:
390
391
```typescript { .api }
392
interface DPoPOptions {
393
/** DPoP handle for proof-of-possession */
394
DPoP?: DPoPHandle;
395
}
396
```
397
398
**Usage with DPoP:**
399
400
```typescript
401
import * as client from "openid-client";
402
403
// Create DPoP key pair
404
const dpopKeyPair = await client.randomDPoPKeyPair();
405
const dpopHandle = client.getDPoPHandle(config, dpopKeyPair);
406
407
// Use with any grant
408
const tokens = await client.clientCredentialsGrant(
409
config,
410
{ scope: "api:access" },
411
{ DPoP: dpopHandle }
412
);
413
414
// Token will be sender-constrained if server supports DPoP
415
if (tokens.token_type === "dpop") {
416
console.log("Token is sender-constrained with DPoP");
417
}
418
```