Skip to content

Commit

Permalink
Merge branch 'master' into refresh_token_fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Diana Khortiuk authored and Diana Khortiuk committed Dec 30, 2024
2 parents 5a2a8ba + 98c6cd6 commit 189d6f6
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 19 deletions.
2 changes: 1 addition & 1 deletion FronteggSwift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FronteggSwift'
s.version = '1.2.26'
s.version = '1.2.27'
s.summary = 'A swift library for easy integrating iOS application with Frontegg Services'
s.description = 'Frontegg is an end-to-end user management platform for B2B SaaS, powering strategies from PLG to enterprise readiness. Easy migration, no credit card required'
s.homepage = 'https://github.com/frontegg/frontegg-ios-swift'
Expand Down
3 changes: 3 additions & 0 deletions Sources/FronteggSwift/FronteggApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class FronteggApp {
/* force consent when authenticate with social login */
public var shouldPromptSocialLoginConsent:Bool = true

public var shouldSuggestSavePassword:Bool = false


public var regionData: [RegionConfig] = []
let credentialManager: CredentialManager
Expand All @@ -46,6 +48,7 @@ public class FronteggApp {
self.bundleIdentifier = bundleIdentifier
self.handleLoginWithSocialLogin = config.loginWithSocialLogin
self.handleLoginWithSSO = config.loginWithSSO
self.shouldSuggestSavePassword = config.shouldSuggestSavePassword

if FronteggApp.clearKeychain(config: config) {
self.credentialManager.clear()
Expand Down
45 changes: 31 additions & 14 deletions Sources/FronteggSwift/FronteggAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ public class FronteggAuth: ObservableObject {

let decode = try JWTHelper.decode(jwtToken: accessToken)
let user = try await self.api.me(accessToken: accessToken)


DispatchQueue.main.sync {
self.refreshToken = refreshToken
self.accessToken = accessToken
Expand All @@ -218,26 +218,26 @@ public class FronteggAuth: ObservableObject {
self.appLink = false
self.initializing = false
self.appLink = false

// isLoading must be at the bottom
self.isLoading = false


let offset = calculateOffset(expirationTime: decode["exp"] as! Int)

scheduleTokenRefresh(offset: offset)

}
} catch {
logger.error("Failed to load user data, \(error)")
logger.error("Failed to load user data: \(error)")
DispatchQueue.main.sync {
self.refreshToken = nil
self.accessToken = nil
self.user = nil
self.isAuthenticated = false
self.initializing = false
self.appLink = false

// isLoading must be at the last bottom
self.isLoading = false
}
Expand Down Expand Up @@ -512,7 +512,7 @@ public class FronteggAuth: ObservableObject {
public typealias ConditionCompletionHandler = (_ error: FronteggError?) -> Void

public func login(_ _completion: FronteggAuth.CompletionHandler? = nil, loginHint: String? = nil) {

if(self.embeddedMode){
self.embeddedLogin(_completion, loginHint: loginHint)
return
Expand All @@ -523,14 +523,30 @@ public class FronteggAuth: ObservableObject {
}

let oauthCallback = createOauthCallbackHandler(completion)
let (authorizeUrl, codeVerifier) = AuthorizeUrlGenerator.shared.generate(loginHint: loginHint)
let (authorizeUrl, codeVerifier) = AuthorizeUrlGenerator.shared.generate(loginHint: loginHint)
CredentialManager.saveCodeVerifier(codeVerifier)


WebAuthenticator.shared.start(authorizeUrl, completionHandler: oauthCallback)

}



func saveWebCredentials(domain: String, email: String, password: String, completion: @escaping (Bool, Error?) -> Void) {
let domainString = domain
let account = email

SecAddSharedWebCredential(domainString as CFString, account as CFString, password as CFString) { error in
if let error = error {
print("❌ Failed to save shared web credentials: \(error.localizedDescription)")
completion(false, error)
} else {
print("✅ Shared web credentials saved successfully!")
completion(true, nil)
}
}
}



public func loginWithPopup(window: UIWindow?, ephemeralSession: Bool? = true, loginHint: String? = nil, loginAction: String? = nil, _completion: FronteggAuth.CompletionHandler? = nil) {

Expand Down Expand Up @@ -725,6 +741,7 @@ public class FronteggAuth: ObservableObject {

func loginWithSocialLogin(socialLoginUrl: String, _ _completion: FronteggAuth.CompletionHandler? = nil) {
let completion = _completion ?? self.loginCompletion ?? { res in


}

Expand Down
20 changes: 20 additions & 0 deletions Sources/FronteggSwift/embedded/FronteggWKContentController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,26 @@ class FronteggWKContentController: NSObject, WKScriptMessageHandler {
FronteggAuth.shared.loginWithSSO(email: message.payload)
case "loginWithSocialLogin":
FronteggAuth.shared.loginWithSocialLogin(socialLoginUrl: message.payload)
case "suggestSavePassword":
guard let data = try? JSONSerialization.jsonObject(with: Data(message.payload.utf8), options: []) as? [String: String],
let email = data["email"],
let password = data["password"] else {
print("Invalid payload for loginWithPassword")

return
}

if let url = URL(string: FronteggAuth.shared.baseUrl), let domain = url.host {
FronteggAuth.shared.saveWebCredentials(domain: domain, email: email, password: password) { success, error in
if success {
print("✅ Credentials saved successfully for \(email)")
} else {
print("❌ Failed to save credentials: \(error?.localizedDescription ?? "Unknown error")")
}
}
} else {
print("❌ Invalid base URL: \(FronteggAuth.shared.baseUrl)")
}
case "showLoader":
FronteggAuth.shared.webLoading = true
case "hideLoader":
Expand Down
3 changes: 2 additions & 1 deletion Sources/FronteggSwift/embedded/FronteggWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public struct FronteggWebView: UIViewRepresentable {
let jsObject = String(data: try! JSONSerialization.data(withJSONObject: [
"loginWithSocialLogin": fronteggApp.handleLoginWithSocialLogin,
"loginWithSSO": fronteggApp.handleLoginWithSSO,
"shouldPromptSocialLoginConsent": fronteggApp.shouldPromptSocialLoginConsent
"shouldPromptSocialLoginConsent": fronteggApp.shouldPromptSocialLoginConsent,
"suggestSavePassword": fronteggApp.shouldSuggestSavePassword
]), encoding: .utf8)

let jsScript = WKUserScript(source: "window.FronteggNativeBridgeFunctions = \(jsObject ?? "{}");", injectionTime: .atDocumentEnd, forMainFrameOnly: false)
Expand Down
11 changes: 10 additions & 1 deletion Sources/FronteggSwift/models/plist/FronteggPlist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct FronteggPlist: Decodable, Equatable {
let payload: Payload
let keepUserLoggedInAfterReinstall: Bool
let useAsWebAuthenticationForAppleLogin: Bool
let shouldSuggestSavePassword:Bool

enum CodingKeys: CodingKey {
case keychainService
Expand All @@ -31,6 +32,7 @@ struct FronteggPlist: Decodable, Equatable {
case logLevel
case keepUserLoggedInAfterReinstall
case useAsWebAuthenticationForAppleLogin
case shouldSuggestSavePassword
}

init(
Expand All @@ -42,7 +44,8 @@ struct FronteggPlist: Decodable, Equatable {
logLevel: LogLevel = .warn,
payload: Payload,
keepUserLoggedInAfterReinstall: Bool,
useAsWebAuthenticationForAppleLogin: Bool = true
useAsWebAuthenticationForAppleLogin: Bool = true,
shouldSuggestSavePassword: Bool = false
) {
self.keychainService = keychainService
self.embeddedMode = embeddedMode
Expand All @@ -53,6 +56,7 @@ struct FronteggPlist: Decodable, Equatable {
self.payload = payload
self.keepUserLoggedInAfterReinstall = keepUserLoggedInAfterReinstall
self.useAsWebAuthenticationForAppleLogin = useAsWebAuthenticationForAppleLogin
self.shouldSuggestSavePassword = shouldSuggestSavePassword
}

init(from decoder: any Decoder) throws {
Expand Down Expand Up @@ -82,6 +86,11 @@ struct FronteggPlist: Decodable, Equatable {
let useAsWebAuthenticationForAppleLogin = try container.decodeIfPresent(Bool.self, forKey: .useAsWebAuthenticationForAppleLogin)
self.useAsWebAuthenticationForAppleLogin = useAsWebAuthenticationForAppleLogin ?? false

let shouldSuggestSavePassword = try container.decodeIfPresent(Bool.self, forKey: .shouldSuggestSavePassword)
self.shouldSuggestSavePassword = shouldSuggestSavePassword ?? false



do {
self.payload = try Payload(from: decoder)
} catch {
Expand Down
2 changes: 2 additions & 0 deletions demo-embedded/demo-embedded/Frontegg.plist
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<true/>
<key>embeddedMode</key>
<true/>
<key>shouldSuggestSavePassword</key>
<true/>
<key>baseUrl</key>
<string>https://autheu.davidantoon.me</string>
<key>clientId</key>
Expand Down
10 changes: 8 additions & 2 deletions demo-embedded/demo-embedded/demo-embedded.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>webcredentials:auth.davidantoon.me</string>
<string>applinks:auth.davidantoon.me</string>
<string>webcredentials:autheu.davidantoon.me</string>
<string>applinks:autheu.davidantoon.me</string>
<string>webcredentials:davidantoon.me</string>
<string>applinks:autheu.davidantoon.me</string>
<string>webcredentials:autheu.davidantoon.me</string>
</array>
<key>com.apple.developer.authentication-services.autofill-credential-provider</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.frontegg.demo</string>
</array>
</dict>
</plist>

0 comments on commit 189d6f6

Please sign in to comment.