17
17
using WalletFramework . Core . Functional ;
18
18
using WalletFramework . Core . Localization ;
19
19
using WalletFramework . MdocVc ;
20
+ using WalletFramework . Oid4Vc . Oid4Vci . Authorization . DPop . Models ;
20
21
using WalletFramework . SdJwtVc . Models . Records ;
21
22
using WalletFramework . SdJwtVc . Services . SdJwtVcHolderService ;
22
23
using static Newtonsoft . Json . JsonConvert ;
@@ -167,6 +168,71 @@ await _authFlowSessionStorage.StoreAsync(
167
168
return authorizationRequestUri ;
168
169
}
169
170
171
+ public async Task < Uri > InitiateAuthFlow ( Uri uri , ClientOptions clientOptions , Option < Locale > language )
172
+ {
173
+ var locale = language . Match (
174
+ some => some ,
175
+ ( ) => Constants . DefaultLocale ) ;
176
+
177
+ var issuerMetadata = _issuerMetadataService . ProcessMetadata ( uri , locale ) ;
178
+
179
+ return await issuerMetadata . Match (
180
+ async validIssuerMetadata =>
181
+ {
182
+ var sessionId = AuthFlowSessionState . CreateAuthFlowSessionState ( ) ;
183
+ var authorizationCodeParameters = CreateAndStoreCodeChallenge ( ) ;
184
+
185
+ var scope = validIssuerMetadata . CredentialConfigurationsSupported . First ( ) . Value . Match (
186
+ sdJwtConfig => sdJwtConfig . CredentialConfiguration . Scope . OnSome ( scope => scope . ToString ( ) ) ,
187
+ mdDocConfig => mdDocConfig . CredentialConfiguration . Scope . OnSome ( scope => scope . ToString ( ) )
188
+ ) ;
189
+
190
+ var par = new PushedAuthorizationRequest (
191
+ sessionId ,
192
+ clientOptions ,
193
+ authorizationCodeParameters ,
194
+ null ,
195
+ scope . ToNullable ( ) ,
196
+ null ,
197
+ null ,
198
+ null ) ;
199
+
200
+ var authServerMetadata =
201
+ await FetchAuthorizationServerMetadataAsync ( validIssuerMetadata ) ;
202
+
203
+ _httpClient . DefaultRequestHeaders . Clear ( ) ;
204
+ var response = await _httpClient . PostAsync (
205
+ authServerMetadata . PushedAuthorizationRequestEndpoint ,
206
+ par . ToFormUrlEncoded ( )
207
+ ) ;
208
+
209
+ var parResponse = DeserializeObject < PushedAuthorizationRequestResponse > ( await response . Content . ReadAsStringAsync ( ) )
210
+ ?? throw new InvalidOperationException ( "Failed to deserialize the PAR response." ) ;
211
+
212
+ var authorizationRequestUri = new Uri ( authServerMetadata . AuthorizationEndpoint
213
+ + "?client_id=" + par . ClientId
214
+ + "&request_uri=" + System . Net . WebUtility . UrlEncode ( parResponse . RequestUri . ToString ( ) ) ) ;
215
+
216
+ //TODO: Select multiple configurationIds
217
+ var authorizationData = new AuthorizationData (
218
+ clientOptions ,
219
+ validIssuerMetadata ,
220
+ authServerMetadata ,
221
+ validIssuerMetadata . CredentialConfigurationsSupported . Keys . ToList ( ) ) ;
222
+
223
+ var context = await _agentProvider . GetContextAsync ( ) ;
224
+ await _authFlowSessionStorage . StoreAsync (
225
+ context ,
226
+ authorizationData ,
227
+ authorizationCodeParameters ,
228
+ sessionId ) ;
229
+
230
+ return authorizationRequestUri ;
231
+ } ,
232
+ _ => throw new Exception ( "Fetching Issuer metadata failed" )
233
+ ) ;
234
+ }
235
+
170
236
public async Task < Validation < OneOf < SdJwtRecord , MdocRecord > > > AcceptOffer ( CredentialOfferMetadata credentialOfferMetadata , string ? transactionCode )
171
237
{
172
238
var issuerMetadata = credentialOfferMetadata . IssuerMetadata ;
@@ -206,7 +272,7 @@ select credentialOrTransactionId.Match(
206
272
{
207
273
var record = sdJwt . Decoded . ToRecord ( configuration . AsT0 , issuerMetadata , response . KeyId ) ;
208
274
var context = await _agentProvider . GetContextAsync ( ) ;
209
- await _sdJwtService . SaveAsync ( context , record ) ;
275
+ await _sdJwtService . AddAsync ( context , record ) ;
210
276
return record ;
211
277
} ,
212
278
async mdoc =>
@@ -237,7 +303,7 @@ from metadata in _issuerMetadataService.ProcessMetadata(offer.CredentialIssuer,
237
303
}
238
304
239
305
/// <inheritdoc />
240
- public async Task < Validation < OneOf < SdJwtRecord , MdocRecord > > > RequestCredential ( IssuanceSession issuanceSession )
306
+ public async Task < Validation < List < OneOf < SdJwtRecord , MdocRecord > > > > RequestCredential ( IssuanceSession issuanceSession )
241
307
{
242
308
var context = await _agentProvider . GetContextAsync ( ) ;
243
309
@@ -248,52 +314,75 @@ public async Task<Validation<OneOf<SdJwtRecord, MdocRecord>>> RequestCredential(
248
314
. IssuerMetadata
249
315
. CredentialConfigurationsSupported
250
316
. Where ( config => session . AuthorizationData . CredentialConfigurationIds . Contains ( config . Key ) )
251
- . Select ( pair => pair . Value )
252
- . First ( ) ;
317
+ . Select ( pair => pair . Value ) ;
318
+
319
+ var scope = session
320
+ . AuthorizationData
321
+ . IssuerMetadata
322
+ . CredentialConfigurationsSupported . First ( ) . Value . Match (
323
+ sdJwtConfig => sdJwtConfig . CredentialConfiguration . Scope . OnSome ( scope => scope . ToString ( ) ) ,
324
+ mdDocConfig => mdDocConfig . CredentialConfiguration . Scope . OnSome ( scope => scope . ToString ( ) ) ) ;
253
325
254
326
var tokenRequest = new TokenRequest
255
327
{
256
328
GrantType = AuthorizationCodeGrantTypeIdentifier ,
257
329
RedirectUri = session . AuthorizationData . ClientOptions . RedirectUri ,
258
330
CodeVerifier = session . AuthorizationCodeParameters . Verifier ,
259
331
Code = issuanceSession . Code ,
332
+ Scope = scope . ToNullable ( ) ,
260
333
ClientId = session . AuthorizationData . ClientOptions . ClientId
261
334
} ;
262
335
263
336
var token = await _tokenService . RequestToken (
264
337
tokenRequest ,
265
338
session . AuthorizationData . AuthorizationServerMetadata ) ;
266
-
267
- var validResponse = await _credentialRequestService . RequestCredentials (
268
- credConfiguration ,
269
- session . AuthorizationData . IssuerMetadata ,
270
- token ,
271
- session . AuthorizationData . ClientOptions ) ;
339
+
340
+ List < OneOf < SdJwtRecord , MdocRecord > > credentials = new ( ) ;
341
+ //TODO: Make sure that it does not always request all available credConfigurations
342
+ foreach ( var configuration in credConfiguration )
343
+ {
344
+ var validResponse = await _credentialRequestService . RequestCredentials (
345
+ configuration ,
346
+ session . AuthorizationData . IssuerMetadata ,
347
+ token ,
348
+ session . AuthorizationData . ClientOptions ) ;
349
+
350
+ var result =
351
+ from response in validResponse
352
+ let cNonce = response . CNonce
353
+ let credentialOrTransactionId = response . CredentialOrTransactionId
354
+ select credentialOrTransactionId . Match (
355
+ async credential => await credential . Value . Match < Task < OneOf < SdJwtRecord , MdocRecord > > > (
356
+ async sdJwt =>
357
+ {
358
+ token = token . Match < OneOf < OAuthToken , DPopToken > > (
359
+ oAuth => oAuth with { CNonce = cNonce . ToNullable ( ) } ,
360
+ dPop => dPop with { Token = dPop . Token with { CNonce = cNonce . ToNullable ( ) } } ) ;
361
+
362
+ var record = sdJwt . Decoded . ToRecord ( configuration . AsT0 , session . AuthorizationData . IssuerMetadata , response . KeyId ) ;
363
+ await _sdJwtService . AddAsync ( context , record ) ;
364
+ return record ;
365
+ } ,
366
+ async mdoc =>
367
+ {
368
+ token = token . Match < OneOf < OAuthToken , DPopToken > > (
369
+ oAuth => oAuth with { CNonce = cNonce . ToNullable ( ) } ,
370
+ dPop => dPop with { Token = dPop . Token with { CNonce = cNonce . ToNullable ( ) } } ) ;
371
+
372
+ var displays = MdocFun . CreateMdocDisplays ( configuration . AsT1 ) ;
373
+ var record = mdoc . Decoded . ToRecord ( displays ) ;
374
+ await _mdocStorage . Add ( record ) ;
375
+ return record ;
376
+ } ) ,
377
+ // ReSharper disable once UnusedParameter.Local
378
+ transactionId => throw new NotImplementedException ( ) ) ;
379
+
380
+ await result . OnSuccess ( async task => credentials . Add ( await task ) ) ;
381
+ }
272
382
273
383
await _authFlowSessionStorage . DeleteAsync ( context , session . AuthFlowSessionState ) ;
274
384
275
- var result =
276
- from response in validResponse
277
- let credentialOrTransactionId = response . CredentialOrTransactionId
278
- select credentialOrTransactionId . Match (
279
- async credential => await credential . Value . Match < Task < OneOf < SdJwtRecord , MdocRecord > > > (
280
- async sdJwt =>
281
- {
282
- var record = sdJwt . Decoded . ToRecord ( credConfiguration . AsT0 , session . AuthorizationData . IssuerMetadata , response . KeyId ) ;
283
- await _sdJwtService . SaveAsync ( context , record ) ;
284
- return record ;
285
- } ,
286
- async mdoc =>
287
- {
288
- var displays = MdocFun . CreateMdocDisplays ( credConfiguration . AsT1 ) ;
289
- var record = mdoc . Decoded . ToRecord ( displays ) ;
290
- await _mdocStorage . Add ( record ) ;
291
- return record ;
292
- } ) ,
293
- // ReSharper disable once UnusedParameter.Local
294
- transactionId => throw new NotImplementedException ( ) ) ;
295
-
296
- return await result . OnSuccess ( task => task ) ;
385
+ return credentials ;
297
386
}
298
387
299
388
private static AuthorizationCodeParameters CreateAndStoreCodeChallenge ( )
0 commit comments