Skip to content

Commit fa07f6e

Browse files
author
dtsiflit
committed
[fix] refresh token updates
1 parent 2a256e4 commit fa07f6e

File tree

2 files changed

+193
-33
lines changed

2 files changed

+193
-33
lines changed

Sources/Issuers/Issuer.swift

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ public protocol IssuerType {
6464
notificationId: NotificationObject,
6565
dPopNonce: Nonce?
6666
) async throws -> Result<Void, Error>
67+
68+
func refresh(
69+
clientId: String,
70+
authorizedRequest: AuthorizedRequest,
71+
dPopNonce: Nonce?
72+
) async -> Result<AuthorizedRequest, Error>
6773
}
6874

6975
public actor Issuer: IssuerType {
@@ -241,17 +247,19 @@ public actor Issuer: IssuerType {
241247

242248
switch response {
243249
case .success(
244-
(let accessToken, let nonce, let identifiers, let expiresIn, let dPopNonce)
250+
(let accessToken, let refreshToken, let nonce, let identifiers, let expiresIn, let dPopNonce)
245251
):
246252
if let cNonce = nonce {
247253
return .success(
248254
.proofRequired(
249-
accessToken: try IssuanceAccessToken(
255+
accessToken: try .init(
250256
accessToken: accessToken.accessToken,
251257
tokenType: accessToken.tokenType,
252-
expiresIn: TimeInterval(expiresIn ?? .zero)
258+
expiresIn: expiresIn?.asTimeInterval ?? .zero
259+
),
260+
refreshToken: try .init(
261+
refreshToken: refreshToken.refreshToken
253262
),
254-
refreshToken: nil,
255263
cNonce: cNonce,
256264
credentialIdentifiers: identifiers,
257265
timeStamp: Date().timeIntervalSinceReferenceDate,
@@ -264,9 +272,11 @@ public actor Issuer: IssuerType {
264272
accessToken: try IssuanceAccessToken(
265273
accessToken: accessToken.accessToken,
266274
tokenType: accessToken.tokenType,
267-
expiresIn: TimeInterval(expiresIn ?? .zero)
275+
expiresIn: expiresIn?.asTimeInterval ?? .zero
276+
),
277+
refreshToken: try .init(
278+
refreshToken: refreshToken.refreshToken
268279
),
269-
refreshToken: nil,
270280
credentialIdentifiers: identifiers,
271281
timeStamp: Date().timeIntervalSinceReferenceDate,
272282
dPopNonce: dPopNonce
@@ -307,6 +317,7 @@ public actor Issuer: IssuerType {
307317

308318
let response: (
309319
accessToken: IssuanceAccessToken,
320+
refreshToken: IssuanceRefreshToken,
310321
nonce: CNonce?,
311322
identifiers: AuthorizationDetailsIdentifiers?,
312323
tokenType: TokenType?,
@@ -323,12 +334,14 @@ public actor Issuer: IssuerType {
323334
if let cNonce = response.nonce {
324335
return .success(
325336
.proofRequired(
326-
accessToken: try IssuanceAccessToken(
337+
accessToken: try .init(
327338
accessToken: response.accessToken.accessToken,
328339
tokenType: response.tokenType,
329340
expiresIn: TimeInterval(response.expiresIn ?? .zero)
330341
),
331-
refreshToken: nil,
342+
refreshToken: try .init(
343+
refreshToken: response.refreshToken.refreshToken
344+
),
332345
cNonce: cNonce,
333346
credentialIdentifiers: response.identifiers,
334347
timeStamp: Date().timeIntervalSinceReferenceDate,
@@ -338,12 +351,14 @@ public actor Issuer: IssuerType {
338351
} else {
339352
return .success(
340353
.noProofRequired(
341-
accessToken: try IssuanceAccessToken(
354+
accessToken: try .init(
342355
accessToken: response.accessToken.accessToken,
343356
tokenType: response.tokenType,
344357
expiresIn: TimeInterval(response.expiresIn ?? .zero)
345358
),
346-
refreshToken: nil,
359+
refreshToken: try .init(
360+
refreshToken: response.refreshToken.refreshToken
361+
),
347362
credentialIdentifiers: response.identifiers,
348363
timeStamp: Date().timeIntervalSinceReferenceDate,
349364
dPopNonce: response.dPopNonce
@@ -838,4 +853,35 @@ public extension Issuer {
838853
dPopNonce: dPopNonce
839854
)
840855
}
856+
857+
func refresh(
858+
clientId: String,
859+
authorizedRequest: AuthorizedRequest,
860+
dPopNonce: Nonce? = nil
861+
) async -> Result<AuthorizedRequest, Error> {
862+
863+
if let refreshToken = authorizedRequest.refreshToken {
864+
do {
865+
let token = try await authorizer.refreshAccessToken(
866+
clientId: clientId,
867+
refreshToken: refreshToken,
868+
dpopNonce: dPopNonce,
869+
retry: true
870+
)
871+
switch token {
872+
case .success((let accessToken, _, _, _, let timeStamp, _)):
873+
return .success(authorizedRequest.replacing(
874+
accessToken: accessToken,
875+
timeStamp: timeStamp?.asTimeInterval ?? .zero
876+
)
877+
)
878+
case .failure(let error):
879+
return .failure(error)
880+
}
881+
} catch {
882+
return .failure(error)
883+
}
884+
}
885+
return .success(authorizedRequest)
886+
}
841887
}

Sources/Main/Authorisers/AuthorizationServerClient.swift

Lines changed: 137 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public protocol AuthorizationServerClientType {
5454
retry: Bool
5555
) async throws -> Result<(
5656
IssuanceAccessToken,
57+
IssuanceRefreshToken,
5758
CNonce?,
5859
AuthorizationDetailsIdentifiers?,
5960
TokenType?,
@@ -71,10 +72,25 @@ public protocol AuthorizationServerClientType {
7172
retry: Bool
7273
) async throws -> Result<(
7374
IssuanceAccessToken,
75+
IssuanceRefreshToken,
7476
CNonce?,
7577
AuthorizationDetailsIdentifiers?,
7678
Int?,
7779
Nonce?), Error>
80+
81+
func refreshAccessToken(
82+
clientId: String,
83+
refreshToken: IssuanceRefreshToken,
84+
dpopNonce: Nonce?,
85+
retry: Bool
86+
) async throws -> Result<(
87+
IssuanceAccessToken,
88+
CNonce?,
89+
AuthorizationDetailsIdentifiers?,
90+
TokenType?,
91+
Int?,
92+
Nonce?
93+
), Error>
7894
}
7995

8096
public actor AuthorizationServerClient: AuthorizationServerClientType {
@@ -313,6 +329,7 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
313329
retry: Bool
314330
) async throws -> Result<(
315331
IssuanceAccessToken,
332+
IssuanceRefreshToken,
316333
CNonce?,
317334
AuthorizationDetailsIdentifiers?,
318335
TokenType?,
@@ -339,7 +356,7 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
339356
)
340357

341358
switch response.body {
342-
case .success(let tokenType, let accessToken, _, let expiresIn, _, let nonce, _, let identifiers):
359+
case .success(let tokenType, let accessToken, let refreshToken, let expiresIn, _, let nonce, _, let identifiers):
343360
return .success(
344361
(
345362
try .init(
@@ -348,6 +365,9 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
348365
value: tokenType
349366
)
350367
),
368+
try .init(
369+
refreshToken: refreshToken
370+
),
351371
.init(
352372
value: nonce
353373
),
@@ -389,27 +409,25 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
389409
}
390410
}
391411

392-
public func requestAccessTokenPreAuthFlow(
393-
preAuthorizedCode: String,
394-
txCode: TxCode?,
412+
public func refreshAccessToken(
395413
clientId: String,
396-
transactionCode: String?,
397-
identifiers: [CredentialConfigurationIdentifier],
414+
refreshToken: IssuanceRefreshToken,
398415
dpopNonce: Nonce?,
399416
retry: Bool
400417
) async throws -> Result<(
401418
IssuanceAccessToken,
402419
CNonce?,
403420
AuthorizationDetailsIdentifiers?,
421+
TokenType?,
404422
Int?,
405-
Nonce?), Error> {
406-
let parameters: JSON = try await preAuthCodeFlow(
407-
preAuthorizedCode: preAuthorizedCode,
408-
txCode: txCode,
409-
clientId: clientId,
410-
transactionCode: transactionCode,
411-
identifiers: identifiers
412-
)
423+
Nonce?
424+
), Error> {
425+
426+
let parameters: JSON = JSON([
427+
Constants.CLIENT_ID_PARAM: clientId,
428+
Constants.GRANT_TYPE_PARAM: Constants.REFRESH_TOKEN,
429+
Constants.REFRESH_TOKEN_PARAM: refreshToken.refreshToken
430+
].compactMapValues { $0 })
413431

414432
do {
415433
let response: ResponseWithHeaders<AccessTokenRequestResponse> = try await service.formPost(
@@ -422,21 +440,34 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
422440
)
423441

424442
switch response.body {
425-
case .success(let tokenType, let accessToken, _, let expiresIn, _, let nonce, _, let identifiers):
443+
case .success(
444+
let tokenType,
445+
let accessToken,
446+
_,
447+
let expiresIn,
448+
_,
449+
let nonce,
450+
_,
451+
let identifiers
452+
):
426453
return .success(
427454
(
428455
try .init(
429456
accessToken: accessToken,
430457
tokenType: .init(
431458
value: tokenType
432-
)
459+
),
460+
expiresIn: TimeInterval(expiresIn)
433461
),
434462
.init(
435463
value: nonce
436464
),
437465
identifiers,
466+
TokenType(
467+
value: tokenType
468+
),
438469
expiresIn,
439-
dpopNonce
470+
response.dpopNonce()
440471
)
441472
)
442473
case .failure(let error, let errorDescription):
@@ -450,14 +481,12 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
450481
switch postError {
451482
case .useDpopNonce(let nonce):
452483
if retry {
453-
return try await requestAccessTokenPreAuthFlow(
454-
preAuthorizedCode: preAuthorizedCode,
455-
txCode: txCode,
484+
return try await refreshAccessToken(
456485
clientId: clientId,
457-
transactionCode: transactionCode,
458-
identifiers: identifiers,
486+
refreshToken: refreshToken,
459487
dpopNonce: nonce,
460-
retry: false)
488+
retry: false
489+
)
461490
} else {
462491
return .failure(ValidationError.retryFailedAfterDpopNonce)
463492
}
@@ -470,6 +499,91 @@ public actor AuthorizationServerClient: AuthorizationServerClientType {
470499
}
471500
}
472501

502+
public func requestAccessTokenPreAuthFlow(
503+
preAuthorizedCode: String,
504+
txCode: TxCode?,
505+
clientId: String,
506+
transactionCode: String?,
507+
identifiers: [CredentialConfigurationIdentifier],
508+
dpopNonce: Nonce?,
509+
retry: Bool
510+
) async throws -> Result<(
511+
IssuanceAccessToken,
512+
IssuanceRefreshToken,
513+
CNonce?,
514+
AuthorizationDetailsIdentifiers?,
515+
Int?,
516+
Nonce?), Error> {
517+
let parameters: JSON = try await preAuthCodeFlow(
518+
preAuthorizedCode: preAuthorizedCode,
519+
txCode: txCode,
520+
clientId: clientId,
521+
transactionCode: transactionCode,
522+
identifiers: identifiers
523+
)
524+
525+
do {
526+
let response: ResponseWithHeaders<AccessTokenRequestResponse> = try await service.formPost(
527+
poster: tokenPoster,
528+
url: tokenEndpoint,
529+
headers: try tokenEndPointHeaders(
530+
dpopNonce: dpopNonce
531+
),
532+
parameters: parameters.toDictionary().convertToDictionaryOfStrings()
533+
)
534+
535+
switch response.body {
536+
case .success(let tokenType, let accessToken, let refreshToken, let expiresIn, _, let nonce, _, let identifiers):
537+
return .success(
538+
(
539+
try .init(
540+
accessToken: accessToken,
541+
tokenType: .init(
542+
value: tokenType
543+
)
544+
),
545+
try .init(
546+
refreshToken: refreshToken
547+
),
548+
.init(
549+
value: nonce
550+
),
551+
identifiers,
552+
expiresIn,
553+
dpopNonce
554+
)
555+
)
556+
case .failure(let error, let errorDescription):
557+
throw CredentialIssuanceError.pushedAuthorizationRequestFailed(
558+
error: error,
559+
errorDescription: errorDescription
560+
)
561+
}
562+
} catch {
563+
if let postError = error as? PostError {
564+
switch postError {
565+
case .useDpopNonce(let nonce):
566+
if retry {
567+
return try await requestAccessTokenPreAuthFlow(
568+
preAuthorizedCode: preAuthorizedCode,
569+
txCode: txCode,
570+
clientId: clientId,
571+
transactionCode: transactionCode,
572+
identifiers: identifiers,
573+
dpopNonce: nonce,
574+
retry: false)
575+
} else {
576+
return .failure(ValidationError.retryFailedAfterDpopNonce)
577+
}
578+
default:
579+
return .failure(error)
580+
}
581+
} else {
582+
return .failure(error)
583+
}
584+
}
585+
}
586+
473587
func toAuthorizationDetail(
474588
credentialConfigurationIds: [CredentialConfigurationIdentifier]
475589
) -> [AuthorizationDetail] {

0 commit comments

Comments
 (0)