@@ -71,6 +71,19 @@ export interface OAuthClientProvider {
7171 * the authorization result.
7272 */
7373 codeVerifier ( ) : string | Promise < string > ;
74+
75+ /**
76+ * The resource to be used for the current session.
77+ *
78+ * Implements RFC 8707 Resource Indicators.
79+ *
80+ * This is placed in the provider to ensure the strong binding between tokens
81+ * and their intended resource throughout the authorization session.
82+ *
83+ * This method is optional and only needs to be implemented if using
84+ * Resource Indicators (RFC 8707).
85+ */
86+ resource ?( ) : string | undefined ;
7487}
7588
7689export type AuthResult = "AUTHORIZED" | "REDIRECT" ;
@@ -142,6 +155,7 @@ export async function auth(
142155 authorizationCode,
143156 codeVerifier,
144157 redirectUri : provider . redirectUrl ,
158+ resource : provider . resource ?.( ) ,
145159 } ) ;
146160
147161 await provider . saveTokens ( tokens ) ;
@@ -158,6 +172,7 @@ export async function auth(
158172 metadata,
159173 clientInformation,
160174 refreshToken : tokens . refresh_token ,
175+ resource : provider . resource ?.( ) ,
161176 } ) ;
162177
163178 await provider . saveTokens ( newTokens ) ;
@@ -170,12 +185,20 @@ export async function auth(
170185 const state = provider . state ? await provider . state ( ) : undefined ;
171186
172187 // Start new authorization flow
173- const { authorizationUrl, codeVerifier } = await startAuthorization ( authorizationServerUrl , {
188+
189+ const resource = provider . resource ?.( ) ;
190+ const { authorizationUrl, codeVerifier } = await startAuthorization ( authorizationServerUrl , {
174191 metadata,
175192 clientInformation,
176193 state,
177194 redirectUrl : provider . redirectUrl ,
178195 scope : scope || provider . clientMetadata . scope ,
196+ /**
197+ * Although RFC 8707 supports multiple resources, we currently only support
198+ * a single resource per auth session to maintain a 1:1 token-resource binding
199+ * based on current auth flow implementation
200+ */
201+ resources : resource ? [ resource ] : undefined ,
179202 } ) ;
180203
181204 await provider . saveCodeVerifier ( codeVerifier ) ;
@@ -310,13 +333,20 @@ export async function startAuthorization(
310333 redirectUrl,
311334 scope,
312335 state,
336+ resources,
313337 } : {
314338 metadata ?: OAuthMetadata ;
315339 clientInformation : OAuthClientInformation ;
316340 redirectUrl : string | URL ;
317341 scope ?: string ;
318342 state ?: string ;
319- } ,
343+ /**
344+ * Array type to align with RFC 8707 which supports multiple resources,
345+ * making it easier to extend for multiple resource indicators in the future
346+ * (though current implementation only uses a single resource)
347+ */
348+ resources ?: string [ ] ;
349+ }
320350) : Promise < { authorizationUrl : URL ; codeVerifier : string } > {
321351 const responseType = "code" ;
322352 const codeChallengeMethod = "S256" ;
@@ -365,6 +395,12 @@ export async function startAuthorization(
365395 authorizationUrl . searchParams . set ( "scope" , scope ) ;
366396 }
367397
398+ if ( resources ?. length ) {
399+ for ( const resource of resources ) {
400+ authorizationUrl . searchParams . append ( "resource" , resource ) ;
401+ }
402+ }
403+
368404 return { authorizationUrl, codeVerifier } ;
369405}
370406
@@ -379,13 +415,15 @@ export async function exchangeAuthorization(
379415 authorizationCode,
380416 codeVerifier,
381417 redirectUri,
418+ resource,
382419 } : {
383420 metadata ?: OAuthMetadata ;
384421 clientInformation : OAuthClientInformation ;
385422 authorizationCode : string ;
386423 codeVerifier : string ;
387424 redirectUri : string | URL ;
388- } ,
425+ resource ?: string ;
426+ }
389427) : Promise < OAuthTokens > {
390428 const grantType = "authorization_code" ;
391429
@@ -412,6 +450,7 @@ export async function exchangeAuthorization(
412450 code : authorizationCode ,
413451 code_verifier : codeVerifier ,
414452 redirect_uri : String ( redirectUri ) ,
453+ ...( resource ? { resource } : { } ) ,
415454 } ) ;
416455
417456 if ( clientInformation . client_secret ) {
@@ -442,11 +481,13 @@ export async function refreshAuthorization(
442481 metadata,
443482 clientInformation,
444483 refreshToken,
484+ resource,
445485 } : {
446486 metadata ?: OAuthMetadata ;
447487 clientInformation : OAuthClientInformation ;
448488 refreshToken : string ;
449- } ,
489+ resource ?: string ;
490+ }
450491) : Promise < OAuthTokens > {
451492 const grantType = "refresh_token" ;
452493
@@ -471,6 +512,7 @@ export async function refreshAuthorization(
471512 grant_type : grantType ,
472513 client_id : clientInformation . client_id ,
473514 refresh_token : refreshToken ,
515+ ...( resource ? { resource } : { } ) ,
474516 } ) ;
475517
476518 if ( clientInformation . client_secret ) {
0 commit comments