@@ -66,6 +66,19 @@ export interface OAuthClientProvider {
6666 * the authorization result.
6767 */
6868 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 ;
6982}
7083
7184export type AuthResult = "AUTHORIZED" | "REDIRECT" ;
@@ -123,6 +136,7 @@ export async function auth(
123136 authorizationCode,
124137 codeVerifier,
125138 redirectUri : provider . redirectUrl ,
139+ resource : provider . resource ?.( ) ,
126140 } ) ;
127141
128142 await provider . saveTokens ( tokens ) ;
@@ -139,6 +153,7 @@ export async function auth(
139153 metadata,
140154 clientInformation,
141155 refreshToken : tokens . refresh_token ,
156+ resource : provider . resource ?.( ) ,
142157 } ) ;
143158
144159 await provider . saveTokens ( newTokens ) ;
@@ -149,12 +164,22 @@ export async function auth(
149164 }
150165
151166 // 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+ ) ;
158183
159184 await provider . saveCodeVerifier ( codeVerifier ) ;
160185 await provider . redirectToAuthorization ( authorizationUrl ) ;
@@ -211,12 +236,19 @@ export async function startAuthorization(
211236 clientInformation,
212237 redirectUrl,
213238 scope,
239+ resources,
214240 } : {
215241 metadata ?: OAuthMetadata ;
216242 clientInformation : OAuthClientInformation ;
217243 redirectUrl : string | URL ;
218244 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+ }
220252) : Promise < { authorizationUrl : URL ; codeVerifier : string } > {
221253 const responseType = "code" ;
222254 const codeChallengeMethod = "S256" ;
@@ -261,6 +293,12 @@ export async function startAuthorization(
261293 authorizationUrl . searchParams . set ( "scope" , scope ) ;
262294 }
263295
296+ if ( resources ?. length ) {
297+ for ( const resource of resources ) {
298+ authorizationUrl . searchParams . append ( "resource" , resource ) ;
299+ }
300+ }
301+
264302 return { authorizationUrl, codeVerifier } ;
265303}
266304
@@ -275,13 +313,15 @@ export async function exchangeAuthorization(
275313 authorizationCode,
276314 codeVerifier,
277315 redirectUri,
316+ resource,
278317 } : {
279318 metadata ?: OAuthMetadata ;
280319 clientInformation : OAuthClientInformation ;
281320 authorizationCode : string ;
282321 codeVerifier : string ;
283322 redirectUri : string | URL ;
284- } ,
323+ resource ?: string ;
324+ }
285325) : Promise < OAuthTokens > {
286326 const grantType = "authorization_code" ;
287327
@@ -308,6 +348,7 @@ export async function exchangeAuthorization(
308348 code : authorizationCode ,
309349 code_verifier : codeVerifier ,
310350 redirect_uri : String ( redirectUri ) ,
351+ ...( resource ? { resource } : { } ) ,
311352 } ) ;
312353
313354 if ( clientInformation . client_secret ) {
@@ -338,11 +379,13 @@ export async function refreshAuthorization(
338379 metadata,
339380 clientInformation,
340381 refreshToken,
382+ resource,
341383 } : {
342384 metadata ?: OAuthMetadata ;
343385 clientInformation : OAuthClientInformation ;
344386 refreshToken : string ;
345- } ,
387+ resource ?: string ;
388+ }
346389) : Promise < OAuthTokens > {
347390 const grantType = "refresh_token" ;
348391
@@ -367,6 +410,7 @@ export async function refreshAuthorization(
367410 grant_type : grantType ,
368411 client_id : clientInformation . client_id ,
369412 refresh_token : refreshToken ,
413+ ...( resource ? { resource } : { } ) ,
370414 } ) ;
371415
372416 if ( clientInformation . client_secret ) {
0 commit comments