Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class Auth0FlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
GetCredentialsRequestHandler(),
SaveCredentialsRequestHandler(),
HasValidCredentialsRequestHandler(),
ClearCredentialsRequestHandler()
ClearCredentialsRequestHandler(),
GetIdTokenContentRequestHandler()
))

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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] {
Expand All @@ -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)

Expand All @@ -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)
}
}

Expand All @@ -113,5 +115,5 @@ public class CredentialsManagerHandler: NSObject, FlutterPlugin {
let methodHandler = methodHandlerProvider(method, credentialsManager)
methodHandler.handle(with: arguments, callback: result)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

Copy link
Contributor

Choose a reason for hiding this comment

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

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)
}
}
Original file line number Diff line number Diff line change
@@ -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)
}
}
8 changes: 7 additions & 1 deletion auth0_flutter/lib/src/mobile/credentials_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ abstract class CredentialsManager {
final Map<String, String> parameters = const {},
});

Future<bool> storeCredentials(final Credentials credentials);
Future<UserInfo> getIDTokenContents();
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be of nullable type ,in the scneario if the credentials aren't available and someone invokes this api ?


Future<bool> storeCredentials(final Credentials credentials);

Future<bool> hasValidCredentials({
final int minTtl = 0,
Expand Down Expand Up @@ -55,6 +57,10 @@ class DefaultCredentialsManager extends CredentialsManager {
parameters: parameters,
)));

@override
Future<UserInfo> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -36,6 +35,11 @@ abstract class CredentialsManagerPlatform extends PlatformInterface {
throw UnimplementedError('getCredentials() has not been implemented');
}

/// Retrieves the credentials from the native storage.
Future<UserInfo> getIDTokenContents(final CredentialsManagerRequest request) {
Copy link
Contributor

@Widcket Widcket Jun 26, 2025

Choose a reason for hiding this comment

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

The Credentials class uses a user property for this. Since this method here is exposing exactly the same functionality (parsing and returning the info contained in the ID token), we should stick to the same naming convention, otherwise it could be confusing. Using different names for the same thing may suggest these are actually different things, or that there is a substantive difference.

throw UnimplementedError('getIDTokenContents() has not been implemented');
}

/// Removes the credentials from the native storage if present.
Future<bool> clearCredentials(final CredentialsManagerRequest request) {
throw UnimplementedError('clearCredentials() has not been implemented');
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 =
Expand Down Expand Up @@ -48,6 +50,12 @@ class MethodChannelCredentialsManager extends CredentialsManagerPlatform {
return result ?? true;
}

@override
Future<UserInfo> getIDTokenContents(final CredentialsManagerRequest request) async {
final Map<String, dynamic> 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.
Expand Down
111 changes: 111 additions & 0 deletions auth0_flutter_platform_interface/lib/src/user_info_credentials.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
class UserIdentity {
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have a User_Profile class defined . Please re use that

final String id;
final String connection;
final String provider;
final bool? isSocial;
final String? accessToken;
final String? accessTokenSecret;
final Map<String, dynamic>? _profileInfo;

UserIdentity({
required this.id,
required this.connection,
required this.provider,
this.isSocial,
this.accessToken,
this.accessTokenSecret,
Map<String, dynamic>? profileInfo})
: _profileInfo = profileInfo ;
factory UserIdentity.fromJson(final Map<String, dynamic> 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<String, dynamic>?
);
}

class UserInfo {
final String? _id;
final List<UserIdentity>? _identities;
final Map<String, dynamic>? _extraInfo;
final Map<String, dynamic>? _userMetadata;
final Map<String, dynamic>? _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<UserIdentity>? identities,
final Map<String, dynamic>? extraInfo,
final Map<String, dynamic>? userMetadata,
final Map<String, dynamic>? 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<String, dynamic> getUserMetadata() =>
_userMetadata ?? {};
Map<String, dynamic> getAppMetadata() =>
_appMetadata ?? {};

List<UserIdentity> getIdentities() =>
_identities ?? [];

Map<String, dynamic> getExtraInfo() =>
_extraInfo ?? {};

factory UserInfo.fromJson(final Map<String, dynamic> 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<dynamic>?)
?.map((e) => UserIdentity.fromJson(e as Map<String, dynamic>))
.toList(),
extraInfo: Map<String, dynamic>.from(json['extraInfo'] as Map),
userMetadata: Map<String, dynamic>.from(json['userMetadata'] as Map),
appMetadata: Map<String, dynamic>.from(json['appMetadata'] as Map),
givenName: json['givenName'] as String?,
);
}
Loading