Skip to content

Commit 2fab17b

Browse files
committed
Add support for disabling credential auto-renewal
1 parent 188878a commit 2fab17b

File tree

4 files changed

+41
-4
lines changed

4 files changed

+41
-4
lines changed

Auth0/CredentialsManager.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public struct CredentialsManager {
2929
private let storage: CredentialsStorage
3030
private let storeKey: String
3131
private let authentication: Authentication
32+
private let allowsAutoRefreshing: Bool
3233
private let dispatchQueue = DispatchQueue(label: "com.auth0.credentialsmanager.serial")
3334
#if WEB_AUTH_PLATFORM
3435
var bioAuth: BioAuthentication?
@@ -40,12 +41,15 @@ public struct CredentialsManager {
4041
/// - authentication: Auth0 Authentication API client.
4142
/// - storeKey: Key used to store user credentials in the Keychain. Defaults to 'credentials'.
4243
/// - storage: The ``CredentialsStorage`` instance used to manage credentials storage. Defaults to a standard `SimpleKeychain` instance.
44+
/// - allowsAutoRefreshing: If `true` (the default), `CredentialsManager` will automatically attempt to refresh credentials using a refresh token.
4345
public init(authentication: Authentication,
4446
storeKey: String = "credentials",
45-
storage: CredentialsStorage = SimpleKeychain()) {
47+
storage: CredentialsStorage = SimpleKeychain(),
48+
allowsAutoRefreshing: Bool = true) {
4649
self.storeKey = storeKey
4750
self.authentication = authentication
4851
self.storage = storage
52+
self.allowsAutoRefreshing = allowsAutoRefreshing
4953
}
5054

5155
/// Retrieves the user information from the Keychain synchronously, without checking if the credentials are expired.
@@ -240,12 +244,13 @@ public struct CredentialsManager {
240244
/// - Returns: If there are credentials stored containing a refresh token.
241245
public func canRenew() -> Bool {
242246
guard let credentials = self.retrieveCredentials() else { return false }
243-
return credentials.refreshToken != nil
247+
return self.allowsAutoRefreshing && credentials.refreshToken != nil
244248
}
245249

246250
#if WEB_AUTH_PLATFORM
247-
/// Retrieves credentials from the Keychain and automatically renews them using the refresh token if the access
248-
/// token is expired. Otherwise, the retrieved credentials will be returned via the success case as they are still
251+
/// Retrieves credentials from the Keychain and automatically renews them (if `allowsAutoRefreshing` is true)
252+
/// using the refresh token if the access token is expired.
253+
/// Otherwise, the retrieved credentials will be returned via the success case as they are still
249254
/// valid. Renewed credentials will be stored in the Keychain. **This method is thread-safe**.
250255
///
251256
/// ## Usage
@@ -652,6 +657,11 @@ public struct CredentialsManager {
652657
dispatchGroup.leave()
653658
return callback(.success(credentials))
654659
}
660+
661+
guard self.allowsAutoRefreshing else {
662+
dispatchGroup.leave()
663+
return callback(.failure(.renewNotSupported))
664+
}
655665
guard let refreshToken = credentials.refreshToken else {
656666
dispatchGroup.leave()
657667
return callback(.failure(.noRefreshToken))

Auth0/CredentialsManagerError.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public struct CredentialsManagerError: Auth0Error, Sendable {
77
case noCredentials
88
case noRefreshToken
99
case renewFailed
10+
case renewNotSupported
1011
case apiExchangeFailed
1112
case ssoExchangeFailed
1213
case storeFailed
@@ -46,6 +47,10 @@ public struct CredentialsManagerError: Auth0Error, Sendable {
4647
/// The underlying ``AuthenticationError`` can be accessed via the ``Auth0Error/cause-9wuyi`` property.
4748
public static let renewFailed: CredentialsManagerError = .init(code: .renewFailed)
4849

50+
/// The credentials renewal is not supported.
51+
/// The underlying ``AuthenticationError`` can be accessed via the ``Auth0Error/cause-9wuyi`` property.
52+
public static let renewNotSupported: CredentialsManagerError = .init(code: .renewNotSupported)
53+
4954
/// The exchange of the refresh token for API credentials failed.
5055
/// The underlying ``AuthenticationError`` can be accessed via the ``Auth0Error/cause-9wuyi`` property.
5156
public static let apiExchangeFailed: CredentialsManagerError = .init(code: .apiExchangeFailed)
@@ -82,6 +87,7 @@ extension CredentialsManagerError {
8287
case .noCredentials: return "No credentials were found in the store."
8388
case .noRefreshToken: return "The stored credentials instance does not contain a refresh token."
8489
case .renewFailed: return "The credentials renewal failed."
90+
case .renewNotSupported: return "Credentials renewal is disabled."
8591
case .apiExchangeFailed: return "The exchange of the refresh token for API credentials failed."
8692
case .ssoExchangeFailed: return "The exchange of the refresh token for SSO credentials failed."
8793
case .storeFailed: return "Storing the renewed credentials failed."

Auth0Tests/CredentialsManagerErrorSpec.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ class CredentialsManagerErrorSpec: QuickSpec {
9797
expect(error.localizedDescription) == message
9898
}
9999

100+
it("should return message for renew failed") {
101+
let message = "Credentials renewal is disabled."
102+
let error = CredentialsManagerError(code: .renewNotSupported)
103+
expect(error.localizedDescription) == message
104+
}
105+
100106
it("should return message for API exchange failed") {
101107
let message = "The exchange of the refresh token for API credentials failed."
102108
let error = CredentialsManagerError(code: .apiExchangeFailed)

Auth0Tests/CredentialsManagerSpec.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,21 @@ class CredentialsManagerSpec: QuickSpec {
666666
}
667667
}
668668
}
669+
670+
it("should not renew if not enabled") {
671+
credentialsManager = CredentialsManager(authentication: authentication,
672+
storage: SimpleKeychain(),
673+
allowsAutoRefreshing: false)
674+
credentials = Credentials(accessToken: AccessToken, tokenType: TokenType, idToken: IdToken, refreshToken: RefreshToken, expiresIn: Date(timeIntervalSinceNow: -ExpiresIn))
675+
_ = credentialsManager.store(credentials: credentials)
676+
677+
waitUntil(timeout: Timeout) { done in
678+
credentialsManager.credentials { result in
679+
expect(result).to(haveCredentialsManagerError(.renewNotSupported))
680+
done()
681+
}
682+
}
683+
}
669684
}
670685

671686
context("forced renewal of credentials") {

0 commit comments

Comments
 (0)