Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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