diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt index 6526066e..96ba87a5 100644 --- a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt @@ -45,7 +45,8 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware { GetCredentialsRequestHandler(), SaveCredentialsRequestHandler(), HasValidCredentialsRequestHandler(), - ClearCredentialsRequestHandler() + ClearCredentialsRequestHandler(), + GetIdTokenContentRequestHandler() )) override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { diff --git a/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetIdTokenContentRequestHandler.kt b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetIdTokenContentRequestHandler.kt new file mode 100644 index 00000000..729d53e8 --- /dev/null +++ b/auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetIdTokenContentRequestHandler.kt @@ -0,0 +1,47 @@ +package com.auth0.auth0_flutter.request_handlers.credentials_manager + +import android.content.Context +import com.auth0.android.authentication.storage.CredentialsManagerException +import com.auth0.android.authentication.storage.SecureCredentialsManager +import com.auth0.auth0_flutter.request_handlers.MethodCallRequest +import io.flutter.plugin.common.MethodChannel +import java.io.Serializable +import java.lang.Exception + + +class GetIdTokenContentRequestHandler: CredentialsManagerRequestHandler { + override val method: String = "credentialsManager#getUserInfo" + override fun handle( + credentialsManager: SecureCredentialsManager, + context: Context, + request: MethodCallRequest, + result: MethodChannel.Result + ) { + result.success( + mapOf( + "id" to credentialsManager.userProfile?.getId(), + "name" to credentialsManager.userProfile?.name, + "nickname" to credentialsManager.userProfile?.nickname, + "pictureURL" to credentialsManager.userProfile?.pictureURL, + "email" to credentialsManager.userProfile?.email, + "isEmailVerified" to credentialsManager.userProfile?.isEmailVerified, + "familyName" to credentialsManager.userProfile?.familyName, + "createdAt" to credentialsManager.userProfile?.createdAt, + "identities" to credentialsManager.userProfile?.getIdentities()?.map { + mapOf( + "provider" to it.provider, + "id" to it.connection, + "isSocial" to it.isSocial, + "accessToken" to it.accessToken, + "accessTokenSecret" to it.accessTokenSecret, + "profileInfo" to it.getProfileInfo() + ) + }, + "extraInfo" to credentialsManager.userProfile?.getExtraInfo(), + "userMetadata" to credentialsManager.userProfile?.getUserMetadata(), + "appMetadata" to credentialsManager.userProfile?.getAppMetadata(), + "givenName" to credentialsManager.userProfile?.givenName + ) + ) + } +} diff --git a/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerHandler.swift b/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerHandler.swift index 17022669..de420156 100644 --- a/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerHandler.swift +++ b/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerHandler.swift @@ -22,6 +22,7 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { case hasValid = "credentialsManager#hasValidCredentials" case get = "credentialsManager#getCredentials" case clear = "credentialsManager#clearCredentials" + case userInfo = "credentialsManager#getUserInfo" } private static let channelName = "auth0.com/auth0_flutter/credentials_manager" @@ -40,7 +41,7 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { registrar.addMethodCallDelegate(handler, channel: channel) } - + func createCredentialManager(_ apiClient: Authentication, _ arguments: [String: Any]) -> CredentialsManager { if let configuration = arguments["credentialsManagerConfiguration"] as? [String: Any], let iosConfiguration = configuration["ios"] as? [String: String] { @@ -65,10 +66,10 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { client.using(inLibrary: userAgent.name, version: userAgent.version) return client } - + lazy var credentialsManagerProvider: CredentialsManagerProvider = { apiClient, arguments in - + var instance = CredentialsManagerHandler.credentialsManager ?? self.createCredentialManager(apiClient,arguments) @@ -89,6 +90,7 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { case .hasValid: return CredentialsManagerHasValidMethodHandler(credentialsManager: credentialsManager) case .get: return CredentialsManagerGetMethodHandler(credentialsManager: credentialsManager) case .clear: return CredentialsManagerClearMethodHandler(credentialsManager: credentialsManager) + case .userInfo: return CredentialsManagerUserInfoMethodHandler(credentialsManager: credentialsManager) } } @@ -113,5 +115,5 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin { let methodHandler = methodHandlerProvider(method, credentialsManager) methodHandler.handle(with: arguments, callback: result) } - + } diff --git a/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerUserInfoMethodHandler.swift b/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerUserInfoMethodHandler.swift new file mode 100644 index 00000000..aa18955c --- /dev/null +++ b/auth0_flutter/darwin/Classes/CredentialsManager/CredentialsManagerUserInfoMethodHandler.swift @@ -0,0 +1,16 @@ + +import Auth0 + +#if os(iOS) +import Flutter +#else +import FlutterMacOS +#endif + +struct CredentialsManagerUserInfoMethodHandler: MethodHandler { + let credentialsManager: CredentialsManager + + func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { + callback(credentialsManager.user) + } +} diff --git a/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerUserInfoMethodHandler.swift b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerUserInfoMethodHandler.swift new file mode 100644 index 00000000..aa18955c --- /dev/null +++ b/auth0_flutter/ios/Classes/CredentialsManager/CredentialsManagerUserInfoMethodHandler.swift @@ -0,0 +1,16 @@ + +import Auth0 + +#if os(iOS) +import Flutter +#else +import FlutterMacOS +#endif + +struct CredentialsManagerUserInfoMethodHandler: MethodHandler { + let credentialsManager: CredentialsManager + + func handle(with arguments: [String: Any], callback: @escaping FlutterResult) { + callback(credentialsManager.user) + } +} diff --git a/auth0_flutter/lib/src/mobile/credentials_manager.dart b/auth0_flutter/lib/src/mobile/credentials_manager.dart index 3b46ed65..ed093403 100644 --- a/auth0_flutter/lib/src/mobile/credentials_manager.dart +++ b/auth0_flutter/lib/src/mobile/credentials_manager.dart @@ -9,7 +9,9 @@ abstract class CredentialsManager { final Map parameters = const {}, }); - Future storeCredentials(final Credentials credentials); + Future getIDTokenContents(); + + Future storeCredentials(final Credentials credentials); Future hasValidCredentials({ final int minTtl = 0, @@ -55,6 +57,10 @@ class DefaultCredentialsManager extends CredentialsManager { parameters: parameters, ))); + @override + Future getIDTokenContents() => + CredentialsManagerPlatform.instance.getIDTokenContents(_createApiRequest(null)); + /// Stores the given credentials in the storage. Must have an `access_token` /// or `id_token` and a `expires_in` value. @override diff --git a/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart b/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart index adccf3e8..1f40b864 100644 --- a/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart +++ b/auth0_flutter_platform_interface/lib/auth0_flutter_platform_interface.dart @@ -25,6 +25,7 @@ export 'src/credentials-manager/options/has_valid_credentials_options.dart'; export 'src/credentials-manager/options/local_authentication.dart'; export 'src/credentials-manager/options/save_credentials_options.dart'; export 'src/credentials.dart'; +export 'src/user_info_credentials.dart'; export 'src/database_user.dart'; export 'src/id_token_validation_config.dart'; export 'src/login_options.dart'; diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart index 6a891e58..3cd2ef35 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/credentials_manager_platform.dart @@ -1,8 +1,7 @@ // coverage:ignore-file import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import '../credentials.dart'; -import '../request/request.dart'; +import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart'; import 'method_channel_credentials_manager.dart'; import 'options/get_credentials_options.dart'; import 'options/has_valid_credentials_options.dart'; @@ -36,6 +35,11 @@ abstract class CredentialsManagerPlatform extends PlatformInterface { throw UnimplementedError('getCredentials() has not been implemented'); } + /// Retrieves the credentials from the native storage. + Future getIDTokenContents(final CredentialsManagerRequest request) { + throw UnimplementedError('getIDTokenContents() has not been implemented'); + } + /// Removes the credentials from the native storage if present. Future clearCredentials(final CredentialsManagerRequest request) { throw UnimplementedError('clearCredentials() has not been implemented'); diff --git a/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart b/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart index 77cd4dfe..9118084d 100644 --- a/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart +++ b/auth0_flutter_platform_interface/lib/src/credentials-manager/method_channel_credentials_manager.dart @@ -1,6 +1,6 @@ import 'package:flutter/services.dart'; -import '../credentials.dart'; +import '../../auth0_flutter_platform_interface.dart'; import '../request/request.dart'; import '../request/request_options.dart'; import 'credentials_manager_exception.dart'; @@ -15,6 +15,8 @@ const String credentialsManagerSaveCredentialsMethod = 'credentialsManager#saveCredentials'; const String credentialsManagerGetCredentialsMethod = 'credentialsManager#getCredentials'; +const String credentialsManagerGetUserProfileMethod = +'credentialsManager#getUserInfo'; const String credentialsManagerClearCredentialsMethod = 'credentialsManager#clearCredentials'; const String credentialsManagerHasValidCredentialsMethod = @@ -48,6 +50,12 @@ class MethodChannelCredentialsManager extends CredentialsManagerPlatform { return result ?? true; } + @override + Future getIDTokenContents(final CredentialsManagerRequest request) async { + final Map result = await _invokeMapRequest(method: credentialsManagerGetUserProfileMethod, request: request); + return UserInfo.fromJson(result); + } + /// Removes the credentials from the native storage if present. /// /// Uses the [MethodChannel] to communicate with the Native platforms. diff --git a/auth0_flutter_platform_interface/lib/src/user_info_credentials.dart b/auth0_flutter_platform_interface/lib/src/user_info_credentials.dart new file mode 100644 index 00000000..417c7a83 --- /dev/null +++ b/auth0_flutter_platform_interface/lib/src/user_info_credentials.dart @@ -0,0 +1,111 @@ +class UserIdentity { +final String id; +final String connection; +final String provider; +final bool? isSocial; +final String? accessToken; +final String? accessTokenSecret; +final Map? _profileInfo; + +UserIdentity({ +required this.id, +required this.connection, +required this.provider, +this.isSocial, +this.accessToken, +this.accessTokenSecret, +Map? profileInfo}) + : _profileInfo = profileInfo ; +factory UserIdentity.fromJson(final Map json) +=> UserIdentity( +connection: json['connection'] as String, +id: json['id'] as String, +isSocial: json['isSocial'] as bool?, +provider: json['provider'] as String, +accessToken: json['accessToken'] as String?, +accessTokenSecret: json['accessTokenSecret'] as String?, +profileInfo: json['profileInfo'] as Map? +); +} + +class UserInfo { +final String? _id; +final List? _identities; +final Map? _extraInfo; +final Map? _userMetadata; +final Map? _appMetadata; + +final String? name; +final String? nickname; +final String? pictureURL; +final String? email; +final bool? isEmailVerified; +final String? familyName; +final DateTime? createdAt; +final String? givenName; + + +UserInfo({ +final String? id, +this.name, +this.nickname, +this.pictureURL, +this.email, +this.isEmailVerified, +this.familyName, +this.createdAt, +final List? identities, +final Map? extraInfo, +final Map? userMetadata, +final Map? appMetadata, +this.givenName, +}) + : _id = id, +_identities = identities, +_extraInfo = extraInfo, +_userMetadata = userMetadata, +_appMetadata = appMetadata; + +String? getId() { +if (_id != null) { +return _id; +} +return (_extraInfo != null && _extraInfo.containsKey('sub')) +? _extraInfo['sub'] as String? + : null; +} + +Map getUserMetadata() => +_userMetadata ?? {}; +Map getAppMetadata() => +_appMetadata ?? {}; + +List getIdentities() => +_identities ?? []; + +Map getExtraInfo() => +_extraInfo ?? {}; + +factory UserInfo.fromJson(final Map json) => +UserInfo( +id: json['id'] as String?, +name: json['name'] as String?, +nickname: json['nickname'] as String?, +pictureURL: json['pictureURL'] as String?, +email: json['email'] as String?, +isEmailVerified: json['isEmailVerified'] as bool?, +familyName: json['familyName'] as String?, +// Handle date parsing +createdAt: json['createdAt'] != null +? DateTime.parse(json['createdAt'] as String) + : null, +// Handle list of UserIdentity +identities: (json['identities'] as List?) + ?.map((e) => UserIdentity.fromJson(e as Map)) + .toList(), +extraInfo: Map.from(json['extraInfo'] as Map), +userMetadata: Map.from(json['userMetadata'] as Map), +appMetadata: Map.from(json['appMetadata'] as Map), +givenName: json['givenName'] as String?, +); +}