@@ -12,7 +12,7 @@ import { INTERNAL_AUTH_PROVIDER_PREFIX } from '../../services/authentication/com
12
12
import { createDecorator } from '../../../platform/instantiation/common/instantiation.js' ;
13
13
import { IExtHostRpcService } from './extHostRpcService.js' ;
14
14
import { URI } from '../../../base/common/uri.js' ;
15
- import { fetchDynamicRegistration , getClaimsFromJWT , IAuthorizationJWTClaims , IAuthorizationServerMetadata , IAuthorizationTokenResponse , isAuthorizationTokenResponse } from '../../../base/common/oauth.js' ;
15
+ import { fetchDynamicRegistration , getClaimsFromJWT , IAuthorizationJWTClaims , IAuthorizationProtectedResourceMetadata , IAuthorizationServerMetadata , IAuthorizationTokenResponse , isAuthorizationTokenResponse } from '../../../base/common/oauth.js' ;
16
16
import { IExtHostWindow } from './extHostWindow.js' ;
17
17
import { IExtHostInitDataService } from './extHostInitDataService.js' ;
18
18
import { ILogger , ILoggerService } from '../../../platform/log/common/log.js' ;
@@ -161,29 +161,47 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
161
161
return Promise . resolve ( ) ;
162
162
}
163
163
164
- async $registerDynamicAuthProvider ( serverMetadata : IAuthorizationServerMetadata , clientId ?: string , initialTokens ?: IAuthorizationToken [ ] ) : Promise < void > {
165
- const issuerUri = URI . parse ( serverMetadata . issuer ) ;
166
- const provider = await DynamicAuthProvider . create (
164
+ async $registerDynamicAuthProvider (
165
+ serverMetadata : IAuthorizationServerMetadata ,
166
+ resourceMetadata : IAuthorizationProtectedResourceMetadata | undefined ,
167
+ clientId : string | undefined ,
168
+ initialTokens : IAuthorizationToken [ ] | undefined
169
+ ) : Promise < string > {
170
+ if ( ! clientId ) {
171
+ if ( ! serverMetadata . registration_endpoint ) {
172
+ throw new Error ( 'Server does not support dynamic registration' ) ;
173
+ }
174
+ try {
175
+ const registration = await fetchDynamicRegistration ( serverMetadata . registration_endpoint , this . _initData . environment . appName ) ;
176
+ clientId = registration . client_id ;
177
+ } catch ( err ) {
178
+ throw new Error ( `Dynamic registration failed: ${ err . message } ` ) ;
179
+ }
180
+ }
181
+ const provider = new DynamicAuthProvider (
167
182
this . _extHostWindow ,
168
183
this . _extHostUrls ,
169
184
this . _initData ,
185
+ this . _extHostLoggerService ,
170
186
this . _proxy ,
171
- this . _extHostLoggerService . createLogger ( serverMetadata . issuer , { name : issuerUri . authority } ) ,
172
187
serverMetadata ,
188
+ resourceMetadata ,
189
+ clientId ,
173
190
this . _onDidDynamicAuthProviderTokensChange ,
174
- { clientId , initialTokens }
191
+ initialTokens || [ ]
175
192
) ;
176
- const disposable = provider . onDidChangeSessions ( e => this . _proxy . $sendDidChangeSessions ( serverMetadata . issuer , e ) ) ;
193
+ const disposable = provider . onDidChangeSessions ( e => this . _proxy . $sendDidChangeSessions ( provider . id , e ) ) ;
177
194
this . _authenticationProviders . set (
178
- serverMetadata . issuer ,
195
+ provider . id ,
179
196
{
180
- label : issuerUri . authority ,
197
+ label : provider . label ,
181
198
provider,
182
199
disposable : Disposable . from ( provider , disposable ) ,
183
200
options : { supportsMultipleAccounts : false }
184
201
}
185
202
) ;
186
- await this . _proxy . $registerDynamicAuthenticationProvider ( serverMetadata . issuer , issuerUri . authority , issuerUri , provider . clientId ) ;
203
+ await this . _proxy . $registerDynamicAuthenticationProvider ( provider . id , provider . label , provider . issuer , provider . clientId ) ;
204
+ return provider . id ;
187
205
}
188
206
189
207
async $onDidChangeDynamicAuthProviderTokens ( authProviderId : string , clientId : string , tokens : IAuthorizationToken [ ] ) : Promise < void > {
@@ -207,28 +225,45 @@ class TaskSingler<T> {
207
225
}
208
226
209
227
export class DynamicAuthProvider implements vscode . AuthenticationProvider {
228
+ readonly id : string ;
229
+ readonly label : string ;
230
+ readonly issuer : URI ;
231
+
210
232
private _onDidChangeSessions = new Emitter < vscode . AuthenticationProviderAuthenticationSessionsChangeEvent > ( ) ;
211
233
readonly onDidChangeSessions = this . _onDidChangeSessions . event ;
212
234
213
235
private readonly _tokenStore : TokenStore ;
214
236
215
237
private readonly _createFlows : Array < ( scopes : string [ ] ) => Promise < IAuthorizationTokenResponse > > ;
216
238
239
+ private readonly _logger : ILogger ;
217
240
private readonly _disposable : DisposableStore ;
218
241
219
242
constructor (
220
243
@IExtHostWindow private readonly _extHostWindow : IExtHostWindow ,
221
244
@IExtHostUrlsService private readonly _extHostUrls : IExtHostUrlsService ,
222
245
@IExtHostInitDataService private readonly _initData : IExtHostInitDataService ,
246
+ @ILoggerService loggerService : ILoggerService ,
223
247
private readonly _proxy : MainThreadAuthenticationShape ,
224
- private readonly _logger : ILogger ,
225
248
private readonly _serverMetadata : IAuthorizationServerMetadata ,
249
+ private readonly _resourceMetadata : IAuthorizationProtectedResourceMetadata | undefined ,
226
250
readonly clientId : string ,
227
- scopedEvent : Event < IAuthorizationToken [ ] > ,
251
+ onDidDynamicAuthProviderTokensChange : Emitter < { authProviderId : string ; clientId : string ; tokens : IAuthorizationToken [ ] } > ,
228
252
initialTokens : IAuthorizationToken [ ] ,
229
253
) {
254
+ this . issuer = URI . parse ( _serverMetadata . issuer ) ;
255
+ this . id = _resourceMetadata ?. resource
256
+ ? _serverMetadata . issuer + ' ' + _resourceMetadata ?. resource
257
+ : _serverMetadata . issuer ;
258
+ this . label = _resourceMetadata ?. resource_name ?? this . issuer . authority ;
259
+
260
+ this . _logger = loggerService . createLogger ( _serverMetadata . issuer , { name : this . label } ) ;
230
261
this . _disposable = new DisposableStore ( ) ;
231
262
this . _disposable . add ( this . _onDidChangeSessions ) ;
263
+ const scopedEvent = Event . chain ( onDidDynamicAuthProviderTokensChange . event , $ => $
264
+ . filter ( e => e . authProviderId === this . id && e . clientId === clientId )
265
+ . map ( e => e . tokens )
266
+ ) ;
232
267
this . _tokenStore = this . _disposable . add ( new TokenStore (
233
268
{
234
269
onDidChange : scopedEvent ,
@@ -242,46 +277,6 @@ export class DynamicAuthProvider implements vscode.AuthenticationProvider {
242
277
this . _createFlows = [ scopes => this . _createWithUrlHandler ( scopes ) ] ;
243
278
}
244
279
245
- static async create (
246
- @IExtHostWindow extHostWindow : IExtHostWindow ,
247
- @IExtHostUrlsService extHostUrls : IExtHostUrlsService ,
248
- @IExtHostInitDataService initData : IExtHostInitDataService ,
249
- proxy : MainThreadAuthenticationShape ,
250
- logger : ILogger ,
251
- serverMetadata : IAuthorizationServerMetadata ,
252
- onDidDynamicAuthProviderTokensChange : Emitter < { authProviderId : string ; clientId : string ; tokens : IAuthorizationToken [ ] } > ,
253
- existingState : { clientId ?: string ; initialTokens ?: IAuthorizationToken [ ] } = { } ,
254
- ) : Promise < DynamicAuthProvider > {
255
- let { clientId, initialTokens } = existingState ;
256
- try {
257
- if ( ! clientId ) {
258
- if ( ! serverMetadata . registration_endpoint ) {
259
- throw new Error ( 'Server does not support dynamic registration' ) ;
260
- }
261
- const registration = await fetchDynamicRegistration ( serverMetadata . registration_endpoint , initData . environment . appName ) ;
262
- clientId = registration . client_id ;
263
- }
264
- const scopedEvent = Event . chain ( onDidDynamicAuthProviderTokensChange . event , $ => $
265
- . filter ( e => e . authProviderId === serverMetadata . issuer && e . clientId === clientId )
266
- . map ( e => e . tokens )
267
- ) ;
268
- const provider = new DynamicAuthProvider (
269
- extHostWindow ,
270
- extHostUrls ,
271
- initData ,
272
- proxy ,
273
- logger ,
274
- serverMetadata ,
275
- clientId ,
276
- scopedEvent ,
277
- initialTokens || [ ]
278
- ) ;
279
- return provider ;
280
- } catch ( err ) {
281
- throw new Error ( `Dynamic registration failed: ${ err . message } ` ) ;
282
- }
283
- }
284
-
285
280
async getSessions ( scopes : readonly string [ ] | undefined , _options : vscode . AuthenticationProviderSessionOptions ) : Promise < vscode . AuthenticationSession [ ] > {
286
281
this . _logger . info ( `Getting sessions for scopes: ${ scopes ?. join ( ' ' ) ?? 'all' } ` ) ;
287
282
if ( ! scopes ) {
@@ -399,6 +394,10 @@ export class DynamicAuthProvider implements vscode.AuthenticationProvider {
399
394
authorizationUrl . searchParams . append ( 'state' , state . toString ( ) ) ;
400
395
authorizationUrl . searchParams . append ( 'code_challenge' , codeChallenge ) ;
401
396
authorizationUrl . searchParams . append ( 'code_challenge_method' , 'S256' ) ;
397
+ if ( this . _resourceMetadata ?. resource ) {
398
+ // If a resource is specified, include it in the request
399
+ authorizationUrl . searchParams . append ( 'resource' , this . _resourceMetadata . resource ) ;
400
+ }
402
401
403
402
// Use a redirect URI that matches what was registered during dynamic registration
404
403
const redirectUri = 'https://vscode.dev/redirect' ;
0 commit comments