@@ -66,6 +66,19 @@ export interface OAuthClientProvider {
66
66
* the authorization result.
67
67
*/
68
68
codeVerifier ( ) : string | Promise < string > ;
69
+
70
+ /**
71
+ * The resource to be used for the current session.
72
+ *
73
+ * Implements RFC 8707 Resource Indicators.
74
+ *
75
+ * This is placed in the provider to ensure the strong binding between tokens
76
+ * and their intended resource throughout the authorization session.
77
+ *
78
+ * This method is optional and only needs to be implemented if using
79
+ * Resource Indicators (RFC 8707).
80
+ */
81
+ resource ?( ) : string | undefined ;
69
82
}
70
83
71
84
export type AuthResult = "AUTHORIZED" | "REDIRECT" ;
@@ -123,6 +136,7 @@ export async function auth(
123
136
authorizationCode,
124
137
codeVerifier,
125
138
redirectUri : provider . redirectUrl ,
139
+ resource : provider . resource ?.( ) ,
126
140
} ) ;
127
141
128
142
await provider . saveTokens ( tokens ) ;
@@ -139,6 +153,7 @@ export async function auth(
139
153
metadata,
140
154
clientInformation,
141
155
refreshToken : tokens . refresh_token ,
156
+ resource : provider . resource ?.( ) ,
142
157
} ) ;
143
158
144
159
await provider . saveTokens ( newTokens ) ;
@@ -149,12 +164,22 @@ export async function auth(
149
164
}
150
165
151
166
// Start new authorization flow
152
- const { authorizationUrl, codeVerifier } = await startAuthorization ( serverUrl , {
153
- metadata,
154
- clientInformation,
155
- redirectUrl : provider . redirectUrl ,
156
- scope : scope || provider . clientMetadata . scope ,
157
- } ) ;
167
+ const resource = provider . resource ?.( ) ;
168
+ const { authorizationUrl, codeVerifier } = await startAuthorization (
169
+ serverUrl ,
170
+ {
171
+ metadata,
172
+ clientInformation,
173
+ redirectUrl : provider . redirectUrl ,
174
+ scope : scope || provider . clientMetadata . scope ,
175
+ /**
176
+ * Although RFC 8707 supports multiple resources, we currently only support
177
+ * a single resource per auth session to maintain a 1:1 token-resource binding
178
+ * based on current auth flow implementation
179
+ */
180
+ resources : resource ? [ resource ] : undefined ,
181
+ }
182
+ ) ;
158
183
159
184
await provider . saveCodeVerifier ( codeVerifier ) ;
160
185
await provider . redirectToAuthorization ( authorizationUrl ) ;
@@ -211,12 +236,19 @@ export async function startAuthorization(
211
236
clientInformation,
212
237
redirectUrl,
213
238
scope,
239
+ resources,
214
240
} : {
215
241
metadata ?: OAuthMetadata ;
216
242
clientInformation : OAuthClientInformation ;
217
243
redirectUrl : string | URL ;
218
244
scope ?: string ;
219
- } ,
245
+ /**
246
+ * Array type to align with RFC 8707 which supports multiple resources,
247
+ * making it easier to extend for multiple resource indicators in the future
248
+ * (though current implementation only uses a single resource)
249
+ */
250
+ resources ?: string [ ] ;
251
+ }
220
252
) : Promise < { authorizationUrl : URL ; codeVerifier : string } > {
221
253
const responseType = "code" ;
222
254
const codeChallengeMethod = "S256" ;
@@ -261,6 +293,12 @@ export async function startAuthorization(
261
293
authorizationUrl . searchParams . set ( "scope" , scope ) ;
262
294
}
263
295
296
+ if ( resources ?. length ) {
297
+ for ( const resource of resources ) {
298
+ authorizationUrl . searchParams . append ( "resource" , resource ) ;
299
+ }
300
+ }
301
+
264
302
return { authorizationUrl, codeVerifier } ;
265
303
}
266
304
@@ -275,13 +313,15 @@ export async function exchangeAuthorization(
275
313
authorizationCode,
276
314
codeVerifier,
277
315
redirectUri,
316
+ resource,
278
317
} : {
279
318
metadata ?: OAuthMetadata ;
280
319
clientInformation : OAuthClientInformation ;
281
320
authorizationCode : string ;
282
321
codeVerifier : string ;
283
322
redirectUri : string | URL ;
284
- } ,
323
+ resource ?: string ;
324
+ }
285
325
) : Promise < OAuthTokens > {
286
326
const grantType = "authorization_code" ;
287
327
@@ -308,6 +348,7 @@ export async function exchangeAuthorization(
308
348
code : authorizationCode ,
309
349
code_verifier : codeVerifier ,
310
350
redirect_uri : String ( redirectUri ) ,
351
+ ...( resource ? { resource } : { } ) ,
311
352
} ) ;
312
353
313
354
if ( clientInformation . client_secret ) {
@@ -338,11 +379,13 @@ export async function refreshAuthorization(
338
379
metadata,
339
380
clientInformation,
340
381
refreshToken,
382
+ resource,
341
383
} : {
342
384
metadata ?: OAuthMetadata ;
343
385
clientInformation : OAuthClientInformation ;
344
386
refreshToken : string ;
345
- } ,
387
+ resource ?: string ;
388
+ }
346
389
) : Promise < OAuthTokens > {
347
390
const grantType = "refresh_token" ;
348
391
@@ -367,6 +410,7 @@ export async function refreshAuthorization(
367
410
grant_type : grantType ,
368
411
client_id : clientInformation . client_id ,
369
412
refresh_token : refreshToken ,
413
+ ...( resource ? { resource } : { } ) ,
370
414
} ) ;
371
415
372
416
if ( clientInformation . client_secret ) {
0 commit comments