Skip to content
59 changes: 44 additions & 15 deletions Auth0/CredentialsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,11 @@ public struct CredentialsManager {
/// ```
///
/// - Parameter audience: Identifier of the API the stored API credentials are for.
/// - Parameter scope: Scope of the stored API credentials. If API credentials are fetched with scope, it is recommended to pass the scope to clear them.
/// - Returns: If the API credentials were removed.
public func clear(forAudience audience: String) -> Bool {
return self.storage.deleteEntry(forKey: audience)
public func clear(forAudience audience: String,scope:String? = nil) -> Bool {
let key = getAPICredentialsStorageKey(audience: audience, scope: scope)
return self.storage.deleteEntry(forKey: key)
}

#if WEB_AUTH_PLATFORM
Expand Down Expand Up @@ -694,23 +696,34 @@ public struct CredentialsManager {
callback: callback)
}

public func store(apiCredentials: APICredentials, forAudience audience: String) -> Bool {
public func store(apiCredentials: APICredentials, forAudience audience: String, forScope scope: String? = nil) -> Bool {
guard let data = try? apiCredentials.encode() else {
return false
}

return self.storage.setEntry(data, forKey: audience)
let key = getAPICredentialsStorageKey(audience: audience, scope: scope)
return self.storage.setEntry(data, forKey: key)
}

private func retrieveCredentials() -> Credentials? {
guard let data = self.storage.getEntry(forKey: self.storeKey) else { return nil }
return try? NSKeyedUnarchiver.unarchivedObject(ofClass: Credentials.self, from: data)
}

private func retrieveAPICredentials(audience: String) -> APICredentials? {
guard let data = self.storage.getEntry(forKey: audience) else { return nil }
private func retrieveAPICredentials(audience: String,scope: String?) -> APICredentials? {
let key = getAPICredentialsStorageKey(audience: audience, scope: scope)
guard let data = self.storage.getEntry(forKey: key) else { return nil }
return try? APICredentials(from: data)
}

private func getAPICredentialsStorageKey(audience: String, scope: String?) -> String {
// Use audience if scope is null else use a combination of audience and scope
if let scope = scope {
return "\(audience)::\(scope.replacingOccurrences(of: " ", with: "::"))"
Copy link
Contributor

@sanchitmehta94 sanchitmehta94 Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion
if we have two scopes like this but the order is different ,
"user.read user.write"
"user.write user.read"

This would create duplicate keys for our cache . would recommend to do something like below
let normalisedScopes = scope
.split(separator: " ")
.sorted()
.joined(separator: "::")

} else {
return audience
}
}

// swiftlint:disable:next function_parameter_count
private func retrieveCredentials(scope: String?,
Expand Down Expand Up @@ -832,10 +845,10 @@ public struct CredentialsManager {
dispatchGroup.enter()

DispatchQueue.global(qos: .userInitiated).async {
if let apiCredentials = self.retrieveAPICredentials(audience: audience),
if let apiCredentials = self.retrieveAPICredentials(audience: audience,scope: scope),
!self.hasExpired(apiCredentials.expiresIn),
!self.willExpire(apiCredentials.expiresIn, within: minTTL),
!self.hasScopeChanged(from: apiCredentials.scope, to: scope) {
!self.hasScopeChanged(from: apiCredentials.scope, to: scope, ignoreOpenid: scope?.contains("openid") == false) {
dispatchGroup.leave()
return callback(.success(apiCredentials))
}
Expand Down Expand Up @@ -867,7 +880,7 @@ public struct CredentialsManager {
} else if !self.store(credentials: newCredentials) {
dispatchGroup.leave()
callback(.failure(CredentialsManagerError(code: .storeFailed)))
} else if !self.store(apiCredentials: newAPICredentials, forAudience: audience) {
} else if !self.store(apiCredentials: newAPICredentials, forAudience: audience, forScope: scope) {
dispatchGroup.leave()
callback(.failure(CredentialsManagerError(code: .storeFailed)))
} else {
Expand All @@ -893,14 +906,30 @@ public struct CredentialsManager {
return expiresIn < Date()
}

func hasScopeChanged(from lastScope: String?, to newScope: String?) -> Bool {
func hasScopeChanged(from lastScope: String?, to newScope: String?, ignoreOpenid: Bool = false) -> Bool {

if let lastScope = lastScope, let newScope = newScope {
let lastScopeList = lastScope.lowercased().split(separator: " ").sorted()
let newScopeList = newScope.lowercased().split(separator: " ").sorted()

return lastScopeList != newScopeList

var storedScopes = Set(
lastScope
.split(separator: " ")
.filter { !$0.isEmpty }
.map { String($0).lowercased() }
)

if ignoreOpenid {
storedScopes.remove("openid")
}

let requiredScopes = Set(
newScope
.split(separator: " ")
.filter { !$0.isEmpty }
.map { String($0).lowercased() }
)

return storedScopes != requiredScopes
}

return false
}

Expand Down
Loading