Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for app state argument #485

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
31 changes: 21 additions & 10 deletions auth0_flutter/lib/auth0_flutter_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,33 @@ class Auth0Web {
/// * Arbitrary [parameters] can be specified and then picked up in a custom
/// Auth0 [Action](https://auth0.com/docs/customize/actions) or
/// [Rule](https://auth0.com/docs/customize/rules).
Future<void> loginWithRedirect(
{final String? audience,
final String? redirectUrl,
final String? organizationId,
final String? invitationUrl,
final int? maxAge,
final Set<String>? scopes,
final Map<String, String> parameters = const {}}) =>
Auth0FlutterWebPlatform.instance.loginWithRedirect(LoginOptions(
/// * The [appState] can be used to pass custom state to the callback URL.
/// This app state can be any value,
/// as long as it can be converted into a Javascript literal.
///
/// See https://api.dart.dev/dart-js_interop/NullableObjectUtilExtension/jsify.html
Future<void> loginWithRedirect({
final Object? appState,
final String? audience,
final String? redirectUrl,
final String? organizationId,
final String? invitationUrl,
final int? maxAge,
final Set<String>? scopes,
final Map<String, String> parameters = const {},
}) =>
Auth0FlutterWebPlatform.instance.loginWithRedirect(
LoginOptions(
appState: appState,
audience: audience,
redirectUrl: redirectUrl,
organizationId: organizationId,
invitationUrl: invitationUrl,
scopes: scopes ?? {},
idTokenValidationConfig: IdTokenValidationConfig(maxAge: maxAge),
parameters: parameters));
parameters: parameters,
),
);

/// Opens a popup with the `/authorize` URL using the parameters provided as
/// parameters.
Expand Down
6 changes: 4 additions & 2 deletions auth0_flutter/lib/src/web/auth0_flutter_plugin_real.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ class Auth0FlutterPlugin extends Auth0FlutterWebPlatform {
: null),
options?.parameters ?? {}));

final loginOptions =
interop.RedirectLoginOptions(authorizationParams: authParams);
final loginOptions = interop.RedirectLoginOptions(
appState: JsInteropUtils.jsifyObject(options?.appState),
authorizationParams: authParams,
);

return client.loginWithRedirect(loginOptions);
}
Expand Down
8 changes: 6 additions & 2 deletions auth0_flutter/lib/src/web/js_interop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,15 @@ class AuthorizationParams {
@JS()
@anonymous
class RedirectLoginOptions {
external Object? get appState; // TODO: use `JSAny?` when migrating to WASM
external AuthorizationParams? get authorizationParams;
external String? get fragment;

external factory RedirectLoginOptions(
{final AuthorizationParams authorizationParams, final String fragment});
external factory RedirectLoginOptions({
final Object? appState,
final AuthorizationParams authorizationParams,
final String fragment,
});
}

@JS()
Expand Down
9 changes: 9 additions & 0 deletions auth0_flutter/lib/src/web/js_interop_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ class JsInteropUtils {

return obj;
}

// TODO: replace with `jsify` from `dart:js_interop_unsafe` when migrating to WASM
/// Convert [obj] to a plain Javascript object.
///
/// This method should only be used to convert objects
/// that do not fit into a static interop definition.
///
/// See https://api.dart.dev/dart-js_interop/NullableObjectUtilExtension/jsify.html
static Object? jsifyObject(final Object? obj) => jsify(obj);
}
1 change: 1 addition & 0 deletions auth0_flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dependency_overrides:

dev_dependencies:
build_runner: ^2.1.8
collection: ^1.18.0
Copy link
Author

Choose a reason for hiding this comment

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

For the MapEquality in the test, hence a dev dependency

dart_jsonwebtoken: ^2.7.1
flutter_lints: ^2.0.1
flutter_test:
Expand Down
10 changes: 9 additions & 1 deletion auth0_flutter/test/mobile/authentication_api_test.mocks.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.4 from annotations
// in auth0_flutter/test/mobile/authentication_api_test.dart.
// Do not manually edit this file.

Expand All @@ -16,6 +16,8 @@ import 'authentication_api_test.dart' as _i4;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
Expand Down Expand Up @@ -87,6 +89,7 @@ class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform {
),
)),
) as _i5.Future<_i2.Credentials>);

@override
_i5.Future<_i2.Credentials> loginWithOtp(
_i3.ApiRequest<_i3.AuthLoginWithOtpOptions>? request) =>
Expand All @@ -103,6 +106,7 @@ class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform {
),
)),
) as _i5.Future<_i2.Credentials>);

@override
_i5.Future<_i3.Challenge> multifactorChallenge(
_i3.ApiRequest<_i3.AuthMultifactorChallengeOptions>? request) =>
Expand All @@ -119,6 +123,7 @@ class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform {
),
)),
) as _i5.Future<_i3.Challenge>);

@override
_i5.Future<_i2.UserProfile> userInfo(
_i3.ApiRequest<_i3.AuthUserInfoOptions>? request) =>
Expand All @@ -135,6 +140,7 @@ class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform {
),
)),
) as _i5.Future<_i2.UserProfile>);

@override
_i5.Future<_i2.DatabaseUser> signup(
_i3.ApiRequest<_i3.AuthSignupOptions>? request) =>
Expand All @@ -151,6 +157,7 @@ class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform {
),
)),
) as _i5.Future<_i2.DatabaseUser>);

@override
_i5.Future<_i2.Credentials> renew(
_i3.ApiRequest<_i3.AuthRenewOptions>? request) =>
Expand All @@ -167,6 +174,7 @@ class MockTestPlatform extends _i1.Mock implements _i4.TestPlatform {
),
)),
) as _i5.Future<_i2.Credentials>);

@override
_i5.Future<void> resetPassword(
_i3.ApiRequest<_i3.AuthResetPasswordOptions>? request) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.4 from annotations
// in auth0_flutter/test/mobile/credentials_manager_test.dart.
// Do not manually edit this file.

Expand All @@ -16,6 +16,8 @@ import 'credentials_manager_test.dart' as _i3;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
Expand Down Expand Up @@ -57,6 +59,7 @@ class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform {
),
)),
) as _i4.Future<_i2.Credentials>);

@override
_i4.Future<bool> clearCredentials(
_i5.CredentialsManagerRequest<_i5.RequestOptions?>? request) =>
Expand All @@ -67,6 +70,7 @@ class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform {
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<bool> saveCredentials(
_i5.CredentialsManagerRequest<_i5.SaveCredentialsOptions>? request) =>
Expand All @@ -77,6 +81,7 @@ class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform {
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<bool> hasValidCredentials(
_i5.CredentialsManagerRequest<_i5.HasValidCredentialsOptions>?
Expand Down
11 changes: 10 additions & 1 deletion auth0_flutter/test/mobile/web_authentication_test.mocks.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.4 from annotations
// in auth0_flutter/test/mobile/web_authentication_test.dart.
// Do not manually edit this file.

Expand All @@ -16,6 +16,8 @@ import 'web_authentication_test.dart' as _i3;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
Expand Down Expand Up @@ -57,6 +59,7 @@ class MockTestPlatform extends _i1.Mock implements _i3.TestPlatform {
),
)),
) as _i4.Future<_i2.Credentials>);

@override
_i4.Future<void> logout(
_i5.WebAuthRequest<_i5.WebAuthLogoutOptions>? request) =>
Expand Down Expand Up @@ -94,6 +97,7 @@ class MockTestCMPlatform extends _i1.Mock implements _i3.TestCMPlatform {
),
)),
) as _i4.Future<_i2.Credentials>);

@override
_i4.Future<bool> clearCredentials(
_i5.CredentialsManagerRequest<_i5.RequestOptions?>? request) =>
Expand All @@ -104,6 +108,7 @@ class MockTestCMPlatform extends _i1.Mock implements _i3.TestCMPlatform {
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<bool> saveCredentials(
_i5.CredentialsManagerRequest<_i5.SaveCredentialsOptions>? request) =>
Expand All @@ -114,6 +119,7 @@ class MockTestCMPlatform extends _i1.Mock implements _i3.TestCMPlatform {
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<bool> hasValidCredentials(
_i5.CredentialsManagerRequest<_i5.HasValidCredentialsOptions>?
Expand Down Expand Up @@ -165,6 +171,7 @@ class MockCredentialsManager extends _i1.Mock
),
)),
) as _i4.Future<_i2.Credentials>);

@override
_i4.Future<bool> storeCredentials(_i2.Credentials? credentials) =>
(super.noSuchMethod(
Expand All @@ -174,6 +181,7 @@ class MockCredentialsManager extends _i1.Mock
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<bool> hasValidCredentials({int? minTtl = 0}) =>
(super.noSuchMethod(
Expand All @@ -184,6 +192,7 @@ class MockCredentialsManager extends _i1.Mock
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<bool> clearCredentials() => (super.noSuchMethod(
Invocation.method(
Expand Down
27 changes: 27 additions & 0 deletions auth0_flutter/test/web/auth0_flutter_web_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:auth0_flutter/src/web/auth0_flutter_plugin_real.dart';
import 'package:auth0_flutter/src/web/auth0_flutter_web_platform_proxy.dart';
import 'package:auth0_flutter/src/web/js_interop.dart' as interop;
import 'package:auth0_flutter_platform_interface/auth0_flutter_platform_interface.dart';
import 'package:collection/collection.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
Expand Down Expand Up @@ -160,6 +161,32 @@ void main() {
expect(params.max_age, null);
});

test('loginWithRedirect supports appState parameter', () async {
Copy link
Author

Choose a reason for hiding this comment

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

New test to verify behavior of the app state

when(mockClientProxy.isAuthenticated())
.thenAnswer((final _) => Future.value(false));

final Map<String, Object?> appState = <String, Object?>{
'someFancyState': 'value',
};

await auth0.loginWithRedirect(
appState: appState,
);

final params =
verify(mockClientProxy.loginWithRedirect(captureAny)).captured.first;

final Object? capturedAppState = dartify(params.appState);

expect(capturedAppState, isNotNull);
expect(capturedAppState, isA<Map<Object?, Object?>>());
capturedAppState as Map<Object?, Object?>;

const MapEquality<Object?, Object?> eq = MapEquality<Object?, Object?>();

expect(eq.equals(capturedAppState, appState), isTrue);
});

test('hasValidCredentials is called without authenticated user', () async {
when(mockClientProxy.isAuthenticated())
.thenAnswer((final _) => Future.value(false));
Expand Down
11 changes: 10 additions & 1 deletion auth0_flutter/test/web/auth0_flutter_web_test.mocks.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.4 from annotations
// in auth0_flutter/test/web/auth0_flutter_web_test.dart.
// Do not manually edit this file.

Expand All @@ -14,6 +14,8 @@ import 'package:mockito/mockito.dart' as _i1;
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
Expand Down Expand Up @@ -59,6 +61,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
Invocation.getter(#client),
),
) as _i2.Auth0Client);

@override
_i4.Future<void> loginWithRedirect(_i2.RedirectLoginOptions? options) =>
(super.noSuchMethod(
Expand All @@ -69,6 +72,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<void> loginWithPopup([
_i2.PopupLoginOptions? options,
Expand All @@ -85,6 +89,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<void> checkSession() => (super.noSuchMethod(
Invocation.method(
Expand All @@ -94,6 +99,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<_i2.WebCredentials> getTokenSilently(
[_i2.GetTokenSilentlyOptions? options]) =>
Expand All @@ -110,6 +116,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
),
)),
) as _i4.Future<_i2.WebCredentials>);

@override
_i4.Future<void> handleRedirectCallback() => (super.noSuchMethod(
Invocation.method(
Expand All @@ -119,6 +126,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<bool> isAuthenticated() => (super.noSuchMethod(
Invocation.method(
Expand All @@ -127,6 +135,7 @@ class MockAuth0FlutterWebClientProxy extends _i1.Mock
),
returnValue: _i4.Future<bool>.value(false),
) as _i4.Future<bool>);

@override
_i4.Future<void> logout(_i2.LogoutOptions? options) => (super.noSuchMethod(
Invocation.method(
Expand Down
Loading