Skip to content

Commit 67e80ce

Browse files
authored
Merge pull request #109 from niscy-eudiw/feature/updated-refresh-token-support
Updated refresh token support
2 parents 231d188 + fa07f6e commit 67e80ce

File tree

7 files changed

+256
-45
lines changed

7 files changed

+256
-45
lines changed

.swiftlint.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
disabled_rules:
2+
- trailing_whitespace

Sources/Entities/Issuance/AuthorizedRequest.swift

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ public extension CanExpire {
2525
if issued >= at {
2626
return true
2727
}
28-
28+
2929
guard let expiresIn = expiresIn else {
3030
return false
3131
}
32-
32+
3333
let expiration = issued + expiresIn
34-
return expiration <= at
34+
return expiration >= at
3535
}
3636
}
3737

@@ -51,24 +51,24 @@ public enum AuthorizedRequest {
5151
timeStamp: TimeInterval,
5252
dPopNonce: Nonce?
5353
)
54-
55-
public func isAccessTokenExpired(clock: TimeInterval) -> Bool {
54+
55+
public func isAccessTokenExpired(_ from: TimeInterval) -> Bool {
5656
guard let timeStamp = self.timeStamp else {
5757
return true
5858
}
59-
return accessToken?.isExpired(issued: timeStamp, at: clock) ?? false
59+
return accessToken?.isExpired(issued: timeStamp, at: from) ?? false
6060
}
61-
61+
6262
public func isRefreshTokenExpired(clock: TimeInterval) -> Bool {
6363
guard let timeStamp = self.timeStamp else {
6464
return true
6565
}
6666
return accessToken?.isExpired(
6767
issued: timeStamp,
6868
at: clock
69-
) ?? false
69+
) ?? false
7070
}
71-
71+
7272
public var timeStamp: TimeInterval? {
7373
switch self {
7474
case .noProofRequired(_, _, _, let timeStamp, _):
@@ -86,7 +86,7 @@ public enum AuthorizedRequest {
8686
return dPopNonce
8787
}
8888
}
89-
89+
9090
public var noProofToken: IssuanceAccessToken? {
9191
switch self {
9292
case .noProofRequired(let accessToken, _, _, _, _):
@@ -95,7 +95,7 @@ public enum AuthorizedRequest {
9595
return nil
9696
}
9797
}
98-
98+
9999
public var proofToken: IssuanceAccessToken? {
100100
switch self {
101101
case .noProofRequired:
@@ -104,6 +104,15 @@ public enum AuthorizedRequest {
104104
return accessToken
105105
}
106106
}
107+
108+
public var refreshToken: IssuanceRefreshToken? {
109+
switch self {
110+
case .noProofRequired(_, let refreshToken, _, _, _):
111+
return refreshToken
112+
case .proofRequired(_, let refreshToken, _, _, _, _):
113+
return refreshToken
114+
}
115+
}
107116
}
108117

109118
public extension AuthorizedRequest {
@@ -132,3 +141,34 @@ public extension AuthorizedRequest {
132141
}
133142
}
134143
}
144+
145+
extension AuthorizedRequest {
146+
/// Returns a copy of the current `AuthorizedRequest`, replacing the `accessToken` and `timeStamp`
147+
/// - Parameters:
148+
/// - newAccessToken: The new `IssuanceAccessToken` to use.
149+
/// - newTimeStamp: The new `TimeInterval` to use.
150+
/// - Returns: A new `AuthorizedRequest` instance with the updated values.
151+
func replacing(accessToken newAccessToken: IssuanceAccessToken, timeStamp newTimeStamp: TimeInterval) -> AuthorizedRequest {
152+
switch self {
153+
case let .noProofRequired(_, refreshToken, credentialIdentifiers, _, dPopNonce):
154+
return .noProofRequired(
155+
accessToken: newAccessToken,
156+
refreshToken: refreshToken,
157+
credentialIdentifiers: credentialIdentifiers,
158+
timeStamp: newTimeStamp,
159+
dPopNonce: dPopNonce
160+
)
161+
162+
case let .proofRequired(_, refreshToken, cNonce, credentialIdentifiers, _, dPopNonce):
163+
return .proofRequired(
164+
accessToken: newAccessToken,
165+
refreshToken: refreshToken,
166+
cNonce: cNonce,
167+
credentialIdentifiers: credentialIdentifiers,
168+
timeStamp: newTimeStamp,
169+
dPopNonce: dPopNonce
170+
)
171+
}
172+
}
173+
}
174+

Sources/Entities/IssuanceRefreshToken.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ public struct IssuanceRefreshToken: Codable, CanExpire {
2020

2121
public let refreshToken: String?
2222

23-
public init(refreshToken: String?) throws {
23+
public init(refreshToken: String?, expiresIn: TimeInterval? = nil) throws {
2424
self.refreshToken = refreshToken
25+
self.expiresIn = expiresIn
2526
}
2627
}
2728

Sources/Extensions/Int+Extensions.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,9 @@ public extension Int {
1919
func isWithinRange(_ range: ClosedRange<Int>) -> Bool {
2020
return range.contains(self)
2121
}
22+
23+
/// Converts an `Int` to a `TimeInterval` (Double).
24+
var asTimeInterval: TimeInterval {
25+
return TimeInterval(self)
26+
}
2227
}

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
}

0 commit comments

Comments
 (0)