Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions auth0_flutter/darwin/auth0_flutter.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Pod::Spec.new do |s|
s.osx.deployment_target = '11.0'
s.osx.dependency 'FlutterMacOS'

s.dependency 'Auth0', '2.23.0'
s.dependency 'JWTDecode', '3.3.0'
s.dependency 'Auth0', '3.0.2'
s.dependency 'JWTDecode', '4.0.0'
s.dependency 'SimpleKeychain', '1.3.0'

# Flutter.framework does not contain a i386 slice.
Expand Down
4 changes: 2 additions & 2 deletions auth0_flutter/darwin/auth0_flutter/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ let package = Package(
.library(name: "auth0-flutter", targets: ["auth0_flutter"]),
],
dependencies: [
.package(url: "https://github.com/auth0/Auth0.swift", exact: "2.23.0"),
.package(url: "https://github.com/auth0/JWTDecode.swift", exact: "3.3.0"),
.package(url: "https://github.com/auth0/Auth0.swift", exact: "3.0.2"),
.package(url: "https://github.com/auth0/JWTDecode.swift", exact: "4.0.0"),
.package(url: "https://github.com/auth0/SimpleKeychain", exact: "1.3.0"),
],
targets: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import FlutterMacOS
// MARK: - Providers

typealias AuthAPIClientProvider = (_ account: Account, _ userAgent: UserAgent, _ arguments: [String: Any]) -> Authentication
typealias AuthAPIMFAClientProvider = (_ account: Account, _ userAgent: UserAgent, _ arguments: [String: Any]) -> MFAClient
typealias AuthAPIMethodHandlerProvider = (_ method: AuthAPIHandler.Method, _ client: Authentication) -> MethodHandler

// MARK: - Auth Auth Handler
Expand Down Expand Up @@ -64,11 +65,21 @@ public class AuthAPIHandler: NSObject, FlutterPlugin {
return client
}

var mfaClientProvider: AuthAPIMFAClientProvider = { account, userAgent, arguments in
var client = Auth0.mfa(clientId: account.clientId, domain: account.domain)
client.using(inLibrary: userAgent.name, version: userAgent.version)

let useDPoP = arguments["useDPoP"] as? Bool ?? false
if useDPoP {
client = client.useDPoP()
}

return client
}

var methodHandlerProvider: AuthAPIMethodHandlerProvider = { method, client in
switch method {
case .loginWithUsernameOrEmail: return AuthAPILoginUsernameOrEmailMethodHandler(client: client)
case .loginWithOTP: return AuthAPILoginWithOTPMethodHandler(client: client)
case .multifactorChallenge: return AuthAPIMultifactorChallengeMethodHandler(client: client)
case .signup: return AuthAPISignupMethodHandler(client: client)
case .userInfo: return AuthAPIUserInfoMethodHandler(client: client)
case .renew: return AuthAPIRenewMethodHandler(client: client)
Expand Down Expand Up @@ -102,6 +113,7 @@ public class AuthAPIHandler: NSObject, FlutterPlugin {
case .passkeyLoginChallenge, .passkeySignupChallenge, .passkeyCredentialExchange:
return UnsupportedMethodHandler()
#endif
case .loginWithOTP, .multifactorChallenge: return UnsupportedMethodHandler()
}
}

Expand All @@ -121,8 +133,16 @@ public class AuthAPIHandler: NSObject, FlutterPlugin {
return result(FlutterMethodNotImplemented)
}

let client = clientProvider(account, userAgent, arguments)
let methodHandler = methodHandlerProvider(method, client)
let methodHandler: MethodHandler
switch method {
case .loginWithOTP:
methodHandler = AuthAPILoginWithOTPMethodHandler(client: mfaClientProvider(account, userAgent, arguments))
case .multifactorChallenge:
methodHandler = AuthAPIMultifactorChallengeMethodHandler(client: mfaClientProvider(account, userAgent, arguments))
default:
let client = clientProvider(account, userAgent, arguments)
methodHandler = methodHandlerProvider(method, client)
}

methodHandler.handle(with: arguments, callback: result)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ struct AuthAPILoginWithOTPMethodHandler: MethodHandler {
case mfaToken
}

let client: Authentication
let client: MFAClient

func handle(with arguments: [String: Any], callback: @escaping FlutterResult) {
guard let otp = arguments[Argument.otp] as? String else {
Expand All @@ -23,7 +23,7 @@ struct AuthAPILoginWithOTPMethodHandler: MethodHandler {
}

client
.login(withOTP: otp, mfaToken: mfaToken)
.verify(otp: otp, mfaToken: mfaToken)
.start {
switch $0 {
case let .success(credentials): callback(result(from: credentials))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum ChallengeProperty: String {
}

fileprivate extension MethodHandler {
func result(from challenge: Challenge) -> Any? {
func result(from challenge: MFAChallenge) -> Any? {
var data: [String: Any] = [ChallengeProperty.challengeType.rawValue: challenge.challengeType]
data[ChallengeProperty.oobCode] = challenge.oobCode
data[ChallengeProperty.bindingMethod] = challenge.bindingMethod
Expand All @@ -28,18 +28,18 @@ struct AuthAPIMultifactorChallengeMethodHandler: MethodHandler {
case authenticatorId
}

let client: Authentication
let client: MFAClient

func handle(with arguments: [String: Any], callback: @escaping FlutterResult) {
guard let mfaToken = arguments[Argument.mfaToken] as? String else {
return callback(FlutterError(from: .requiredArgumentMissing(Argument.mfaToken.rawValue)))
}

let types = arguments[Argument.types] as? [String]
let authenticatorId = arguments[Argument.authenticatorId] as? String
guard let authenticatorId = arguments[Argument.authenticatorId] as? String else {
return callback(FlutterError(from: .requiredArgumentMissing(Argument.authenticatorId.rawValue)))
}

client
.multifactorChallenge(mfaToken: mfaToken, types: types, authenticatorId: authenticatorId)
.challenge(with: authenticatorId, mfaToken: mfaToken)
.start {
switch $0 {
case let .success(challenge): callback(result(from: challenge))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct AuthAPIPasskeyCredentialExchangeMethodHandler: MethodHandler {
let response = credentialMap["response"] as? [String: Any]
let isSignup = response?["attestationObject"] != nil

let request: Request<Credentials, AuthenticationError>
let request: any TokenRequestable<Credentials, AuthenticationError>
if isSignup {
guard let challenge = Self.reconstructSignupChallenge(from: challengeMap) else {
return callback(FlutterError(code: "PASSKEY_ERROR",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import FlutterMacOS
#endif

fileprivate extension MethodHandler {
func result(from userInfo: UserInfo) -> Any? {
func result(from userInfo: UserProfile) -> Any? {
return userInfo.asDictionary()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct SSOExchangeMethodHandler: MethodHandler {
var response: [String: Any] = [
"sessionTransferToken": ssoCredentials.sessionTransferToken,
"tokenType": ssoCredentials.issuedTokenType,
"expiresIn": Int(ssoCredentials.expiresIn.timeIntervalSinceNow)
"expiresIn": Int(ssoCredentials.expiresAt.timeIntervalSinceNow)
]
response["idToken"] = ssoCredentials.idToken
if let refreshToken = ssoCredentials.refreshToken {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ struct ClearApiCredentialsMethodHandler: MethodHandler {
}
let scope = arguments[Argument.scope] as? String

callback(self.credentialsManager.clear(forAudience: audience, scope: scope))
do {
try self.credentialsManager.clear(forAudience: audience, scope: scope)
callback(nil)
} catch {
callback(FlutterError(from: (error as? CredentialsManagerError) ?? .unknown))
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ struct CredentialsManagerClearMethodHandler: MethodHandler {
let credentialsManager: CredentialsManager

func handle(with arguments: [String: Any], callback: @escaping FlutterResult) {
callback(self.credentialsManager.clear())
do {
try self.credentialsManager.clear()
callback(true)
Comment thread
NandanPrabhu marked this conversation as resolved.
} catch {
callback(FlutterError(from: (error as? CredentialsManagerError) ?? .unknown))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ struct CredentialsManagerSaveMethodHandler: MethodHandler {
return callback(FlutterError(from: .requiredArgumentMissing(Argument.credentials.rawValue)))
}

callback(self.credentialsManager.store(credentials: credentials))
do {
try self.credentialsManager.store(credentials: credentials)
callback(true)
Comment thread
NandanPrabhu marked this conversation as resolved.
} catch {
callback(FlutterError(from: (error as? CredentialsManagerError) ?? .unknown))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ struct CredentialsManagerUserInfoMethodHandler: MethodHandler {
let credentialsManager: CredentialsManager

func handle(with arguments: [String: Any], callback: @escaping FlutterResult) {
if let user = credentialsManager.user {
callback(user.asDictionary())
} else {
callback(nil)
do {
let user = try credentialsManager.userProfile()
callback(user?.asDictionary())
} catch {
callback(FlutterError(from: (error as? CredentialsManagerError) ?? .unknown))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct SSOCredentialsMethodHandler: MethodHandler {
var response: [String: Any] = [
"sessionTransferToken": ssoCredentials.sessionTransferToken,
"tokenType": ssoCredentials.issuedTokenType,
"expiresIn": Int(ssoCredentials.expiresIn.timeIntervalSinceNow)
"expiresIn": Int(ssoCredentials.expiresAt.timeIntervalSinceNow)
]
response["idToken"] = ssoCredentials.idToken
if let refreshToken = ssoCredentials.refreshToken {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ extension Credentials {
tokenType: tokenType,
idToken: idToken,
refreshToken: dictionary[CredentialsProperty.refreshToken] as? String,
expiresIn: expiresIn,
expiresAt: expiresIn,
scope: scopes.isEmpty ? nil : scopes.asSpaceSeparatedString,
recoveryCode: nil)
}
Expand All @@ -85,9 +85,9 @@ extension Credentials {
var data: [String: Any] = [
CredentialsProperty.accessToken.rawValue: accessToken,
CredentialsProperty.idToken.rawValue: idToken,
CredentialsProperty.expiresAt.rawValue: expiresIn.asISO8601String,
CredentialsProperty.expiresAt.rawValue: expiresAt.asISO8601String,
CredentialsProperty.scopes.rawValue: scope?.split(separator: " ").map(String.init) ?? [],
CredentialsProperty.userProfile.rawValue: UserInfo(json: jwt.body)?.asDictionary() ?? [:],
CredentialsProperty.userProfile.rawValue: UserProfile(json: jwt.body)?.asDictionary() ?? [:],
CredentialsProperty.tokenType.rawValue: tokenType
]
data[CredentialsProperty.refreshToken] = refreshToken
Expand All @@ -100,13 +100,13 @@ extension APICredentials {
return [
"accessToken": accessToken,
"tokenType": tokenType,
"expiresAt": expiresIn.asISO8601String,
"expiresAt": expiresAt.asISO8601String,
"scopes": scope.split(separator: " ").map(String.init)
]
}
}

extension UserInfo {
extension UserProfile {
func asDictionary() -> [String: Any] {
let claimsToFilter = ["aud",
"iss",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct MfaEnrollPushMethodHandler: MethodHandler {
return callback(FlutterError(from: .requiredArgumentMissing("mfaToken")))
}

let request: Request<PushMFAEnrollmentChallenge, MfaEnrollmentError> =
let request: any Requestable<PushMFAEnrollmentChallenge, MfaEnrollmentError> =
client.enroll(mfaToken: mfaToken)
request.start {
switch $0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct MfaEnrollTotpMethodHandler: MethodHandler {
return callback(FlutterError(from: .requiredArgumentMissing("mfaToken")))
}

let request: Request<OTPMFAEnrollmentChallenge, MfaEnrollmentError> =
let request: any Requestable<OTPMFAEnrollmentChallenge, MfaEnrollmentError> =
client.enroll(mfaToken: mfaToken)
request.start {
switch $0 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct MfaVerifyMethodHandler: MethodHandler {
return callback(FlutterError(from: .requiredArgumentMissing("grantType")))
}

let request: Request<Credentials, MFAVerifyError>
let request: any TokenRequestable<Credentials, MFAVerifyError>

switch grantType {
case "otp":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct MyAccountConfirmEnrollmentMethodHandler: MethodHandler {
return callback(FlutterError(from: .requiredArgumentMissing("factorType")))
}

let request: Request<AuthenticationMethod, MyAccountError>
let request: any Requestable<AuthenticationMethod, MyAccountError>
if factorType == "push-notification" {
request = client.authenticationMethods.confirmPushNotificationEnrollment(id: id, authSession: authSession)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct MyAccountVerifyOtpMethodHandler: MethodHandler {
return callback(FlutterError(from: .requiredArgumentMissing("factorType")))
}

let request: Request<AuthenticationMethod, MyAccountError>
let request: any Requestable<AuthenticationMethod, MyAccountError>
switch factorType {
case "email":
request = client.authenticationMethods.confirmEmailEnrollment(id: id, authSession: authSession, otpCode: otp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ extension FlutterError {
convenience init(from webAuthError: WebAuthError) {
var code: String
switch webAuthError {
case WebAuthError.noBundleIdentifier: code = "NO_BUNDLE_IDENTIFIER"
case WebAuthError.invalidInvitationURL: code = "INVALID_INVITATION_URL"
case WebAuthError.userCancelled: code = "USER_CANCELLED"
case WebAuthError.noAuthorizationCode: code = "NO_AUTHORIZATION_CODE"
case WebAuthError.pkceNotAllowed: code = "PKCE_NOT_ALLOWED"
case WebAuthError.authenticationFailed: code = "AUTHENTICATION_FAILED"
case WebAuthError.codeExchangeFailed: code = "CODE_EXCHANGE_FAILED"
case WebAuthError.idTokenValidationFailed: code = "ID_TOKEN_VALIDATION_FAILED"
case WebAuthError.credentialsManagerError: code = "CREDENTIALS_MANAGER_ERROR"
case WebAuthError.transactionActiveAlready: code = "TRANSACTION_ACTIVE_ALREADY"
case WebAuthError.other: code = "OTHER"
default: code = "UNKNOWN"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import FlutterMacOS
#endif

#if os(iOS)
typealias WebAuthProviderFunction = (UIModalPresentationStyle) -> WebAuthProvider
typealias WebAuthProviderFunction = @MainActor (UIModalPresentationStyle) -> WebAuthProvider
#endif

struct WebAuthLoginMethodHandler: MethodHandler {
Expand All @@ -35,7 +35,9 @@ struct WebAuthLoginMethodHandler: MethodHandler {
#if os(iOS)
let safariProvider: WebAuthProviderFunction

init(client: WebAuth, safariProvider: @escaping WebAuthProviderFunction = WebAuthentication.safariProvider) {
init(client: WebAuth, safariProvider: @escaping WebAuthProviderFunction = { style in
WebAuthentication.safariProvider(style: style)
}) {
self.client = client
self.safariProvider = safariProvider
}
Expand Down Expand Up @@ -103,7 +105,11 @@ struct WebAuthLoginMethodHandler: MethodHandler {
#if os(iOS)
if let safariViewControllerDictionary = arguments[SafariViewController.key] as? [String: Any?] {
let safariViewController = SafariViewController(from: safariViewControllerDictionary)
webAuth = webAuth.provider(self.safariProvider(safariViewController.presentationStyle))
// Flutter dispatches method calls on the main thread, so this is safe to assert.
let provider = MainActor.assumeIsolated {
self.safariProvider(safariViewController.presentationStyle)
}
webAuth = webAuth.provider(provider)
}
#endif

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ struct WebAuthLogoutMethodHandler: MethodHandler {
webAuth = webAuth.redirectURL(url)
}

webAuth.clearSession(federated: federated) { // Pass federated here
webAuth.logout(federated: federated) { // Pass federated here
switch $0 {
case .success: callback(nil)
case let .failure(error): callback(FlutterError(from: error))
Expand Down
3 changes: 3 additions & 0 deletions auth0_flutter/example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
end
Loading
Loading