Skip to content

chore(auth): hosted ui platforms to use AmplifyOutputs types instead of AmplifyConfig #5273

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

Merged
merged 1 commit into from
Aug 14, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:amplify_auth_cognito/src/native_auth_plugin.g.dart';
import 'package:amplify_auth_cognito_dart/src/state/state.dart';
import 'package:amplify_auth_cognito_test/amplify_auth_cognito_test.dart';
import 'package:amplify_auth_integration_test/amplify_auth_integration_test.dart';
import 'package:amplify_core/src/config/amplify_outputs/auth/auth_outputs.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
Expand All @@ -34,7 +35,7 @@ void main() {

setUp(() async {
dependencyManager = DependencyManager()
..addInstance<CognitoOAuthConfig>(hostedUiConfig)
..addInstance<AuthOutputs>(mockConfig.auth!)
..addInstance<SecureStorageInterface>(MockSecureStorage())
..addInstance<http.Client>(
MockClient((request) {
Expand All @@ -58,7 +59,7 @@ void main() {
argPreferprivatesession,
argBrowserpackagename,
) async {
expect(argUrl, contains(hostedUiConfig.webDomain));
expect(argUrl, contains(mockConfig.auth?.oauth?.domain));
expect(argCallbackurlscheme, testUrlScheme);
expect(argPreferprivatesession, isFalse);
expect(argBrowserpackagename, browserPackage);
Expand Down Expand Up @@ -86,7 +87,7 @@ void main() {
argPreferprivatesession,
argBrowserpackagename,
) async {
expect(argUrl, contains(hostedUiConfig.webDomain));
expect(argUrl, contains(mockConfig.auth?.oauth?.domain));
expect(argCallbackurlscheme, testUrlScheme);
expect(argPreferprivatesession, isFalse);
expect(argBrowserpackagename, browserPackage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@ class HostedUiPlatformImpl extends io.HostedUiPlatformImpl {
if (!_isMobile) {
return super.signInRedirectUri;
}
return config.signInRedirectUris.firstWhere(
(uri) => uri.scheme != 'https' && uri.scheme != 'http',
orElse: () => _noSuitableRedirect(signIn: true),
);
return authOutputs.oauth!.redirectSignInUri.map(Uri.parse).firstWhere(
(uri) => uri.scheme != 'https' && uri.scheme != 'http',
orElse: () => _noSuitableRedirect(signIn: true),
);
}

@override
Uri get signOutRedirectUri {
if (!_isMobile) {
return super.signOutRedirectUri;
}
return config.signOutRedirectUris.firstWhere(
(uri) => uri.scheme != 'https' && uri.scheme != 'http',
orElse: () => _noSuitableRedirect(signIn: false),
);
return authOutputs.oauth!.redirectSignOutUri.map(Uri.parse).firstWhere(
(uri) => uri.scheme != 'https' && uri.scheme != 'http',
orElse: () => _noSuitableRedirect(signIn: false),
);
}

@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void main() {
setUp(() async {
secureStorage = MockSecureStorage();
dependencyManager = DependencyManager()
..addInstance(hostedUiConfig)
..addInstance(mockConfig.auth!)
..addInstance<SecureStorageInterface>(secureStorage)
..addInstance<NativeAuthBridge>(ThrowingNativeBridge());
plugin = AmplifyAuthCognito()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,23 @@
// SPDX-License-Identifier: Apache-2.0

import 'package:amplify_core/amplify_core.dart';

/// Configuration helpers for [CognitoUserPoolConfig].
extension HostedUiJwks on CognitoUserPoolConfig {
/// The JSON Web Key (JWK) URI.
///
/// References:
/// - https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
Uri get jwksUri => Uri.parse(
'https://cognito-idp.$region.amazonaws.com/$poolId/.well-known/jwks.json',
);
}
Comment on lines -5 to -15
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: Why was this removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't find any usage of this in the code base and so cleaned up the unused code.

// ignore: implementation_imports
import 'package:amplify_core/src/config/amplify_outputs/auth/oauth_outputs.dart';

/// Configuration helpers for [CognitoOAuthConfig].
///
/// [Reference](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-userpools-server-contract-reference.html)
extension HostedUiConfig on CognitoOAuthConfig {
/// The parsed [webDomain] URI.
extension HostedUiConfig on OAuthOutputs {
/// The parsed [domain] URI.
///
/// If [webDomain] specifies a scheme, it is honored in requests in the same
/// If [domain] specifies a scheme, it is honored in requests in the same
/// way that it is honored for [signInUri], [tokenUri], and [signOutUri]. If
/// no scheme is specified, it defaults to `https` and [webDomain] is
/// no scheme is specified, it defaults to `https` and [domain] is
/// interpreted as a host string.
Uri get _webDomain {
final uri = Uri.parse(webDomain);
final uri = Uri.parse(domain);
if (uri.hasScheme) return uri;
return Uri(scheme: 'https', host: webDomain);
return Uri(scheme: 'https', host: domain);
}

/// The sign in URI.
Expand All @@ -37,14 +28,17 @@ extension HostedUiConfig on CognitoOAuthConfig {
/// - https://docs.aws.amazon.com/cognito/latest/developerguide/login-endpoint.html
Uri signInUri([AuthProvider? provider]) {
Uri baseUri;
// ignore: invalid_use_of_internal_member
if (this.signInUri != null) {
// ignore: invalid_use_of_internal_member
baseUri = Uri.parse(this.signInUri!);
} else {
baseUri = _webDomain.replace(path: '/oauth2/authorize');
}
return baseUri.replace(
queryParameters: <String, String>{
if (provider != null) 'identity_provider': provider.uriParameter,
// ignore: invalid_use_of_internal_member
...?signInUriQueryParameters,
},
);
Expand All @@ -54,51 +48,43 @@ extension HostedUiConfig on CognitoOAuthConfig {
///
/// References:
/// - https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html
Uri get signOutUri {
Uri signOutUri(String userPoolClientId) {
return _webDomain.replace(
path: '/logout',
queryParameters: <String, String>{
// ignore: invalid_use_of_internal_member
...?signOutUriQueryParameters,
'client_id': appClientId,
'client_id': userPoolClientId,
},
);
}

/// The sign in redirect URI to use.
///
/// Throws a [StateError] if there are no URIs registered.
Uri get signInRedirectUri => signInRedirectUris.first;
Uri get signInRedirectUri => Uri.parse(redirectSignInUri.first);

/// The sign out redirect URI to use.
///
/// Throws a [StateError] if there are no URIs registered.
Uri get signOutRedirectUri => signOutRedirectUris.first;
Uri get signOutRedirectUri => Uri.parse(redirectSignOutUri.first);

/// The `token` URI.
///
/// References:
/// - https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html
Uri get tokenUri {
Uri baseUri;
// ignore: invalid_use_of_internal_member
if (this.tokenUri != null) {
// ignore: invalid_use_of_internal_member
baseUri = Uri.parse(this.tokenUri!);
} else {
baseUri = _webDomain.replace(path: '/oauth2/token');
}
return baseUri.replace(
// ignore: invalid_use_of_internal_member
queryParameters: tokenUriQueryParameters,
);
}

/// The `revoke` URI.
///
/// References:
/// - https://docs.aws.amazon.com/cognito/latest/developerguide/revocation-endpoint.html
Uri get revocationUri => _webDomain.replace(path: '/oauth2/revoke');

/// The `userinfo` URI.
///
/// References:
/// - https://docs.aws.amazon.com/cognito/latest/developerguide/userinfo-endpoint.html
Uri get userInfoUri => _webDomain.replace(path: '/oauth2/userInfo');
Comment on lines -92 to -103
Copy link
Contributor

Choose a reason for hiding this comment

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

Q: do these need to be replaced?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't find any usage of these in the code base and so cleaned up the unused code.

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import 'package:amplify_auth_cognito_dart/src/flows/hosted_ui/hosted_ui_platform
import 'package:amplify_auth_cognito_dart/src/model/hosted_ui/oauth_parameters.dart';
import 'package:amplify_auth_cognito_dart/src/state/state.dart';
import 'package:amplify_core/amplify_core.dart';
// ignore: implementation_imports
import 'package:amplify_core/src/config/amplify_outputs/auth/auth_outputs.dart';
// ignore: implementation_imports
import 'package:amplify_core/src/config/amplify_outputs/auth/oauth_outputs.dart';
import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart';
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
Expand All @@ -35,12 +39,18 @@ abstract class HostedUiPlatform implements Closeable {
@protected
HostedUiPlatform.protected(this.dependencyManager);

/// The Hosted UI configuration.
/// The Auth configuration.
@protected
CognitoOAuthConfig get config => dependencyManager.expect();
AuthOutputs get authOutputs {
final authOutputs = dependencyManager.get<AuthOutputs>();
if (authOutputs?.oauth == null || authOutputs?.userPoolClientId == null) {
throw const InvalidAccountTypeException.noUserPool();
}
return authOutputs!;
}

/// The Hosted UI storage keys.
late final HostedUiKeys _keys = HostedUiKeys(config.appClientId);
late final HostedUiKeys _keys = HostedUiKeys(authOutputs.userPoolClientId!);

/// The secure storage plugin.
SecureStorageInterface get _secureStorage => dependencyManager.getOrCreate();
Expand Down Expand Up @@ -114,14 +124,16 @@ abstract class HostedUiPlatform implements Closeable {
);

_authCodeGrant = createGrant(
config,
authOutputs.oauth!, authOutputs.userPoolClientId!,
// ignore: invalid_use_of_internal_member
appClientSecret: authOutputs.appClientSecret,
codeVerifier: codeVerifier,
httpClient: httpClient,
provider: provider,
);
final uri = _authCodeGrant!.getAuthorizationUrl(
redirectUri ?? signInRedirectUri,
scopes: config.scopes,
scopes: authOutputs.oauth?.scopes,
state: state,
);

Expand All @@ -137,7 +149,8 @@ abstract class HostedUiPlatform implements Closeable {
@visibleForTesting
@nonVirtual
Uri getSignOutUri({Uri? redirectUri}) {
final signOutUri = HostedUiConfig(config).signOutUri;
final signOutUri = HostedUiConfig(authOutputs.oauth!)
.signOutUri(authOutputs.userPoolClientId!);

return signOutUri.replace(
queryParameters: <String, String>{
Expand All @@ -152,16 +165,18 @@ abstract class HostedUiPlatform implements Closeable {
@visibleForTesting
@nonVirtual
oauth2.AuthorizationCodeGrant createGrant(
CognitoOAuthConfig config, {
OAuthOutputs oauthOutputs,
String userPoolClientId, {
String? appClientSecret,
AuthProvider? provider,
String? codeVerifier,
http.Client? httpClient,
}) {
return oauth2.AuthorizationCodeGrant(
config.appClientId,
HostedUiConfig(config).signInUri(provider),
HostedUiConfig(config).tokenUri,
secret: config.appClientSecret,
userPoolClientId,
HostedUiConfig(authOutputs.oauth!).signInUri(provider),
HostedUiConfig(authOutputs.oauth!).tokenUri,
secret: appClientSecret,
httpClient: httpClient,
codeVerifier: codeVerifier,

Expand All @@ -177,13 +192,15 @@ abstract class HostedUiPlatform implements Closeable {
@visibleForTesting
@nonVirtual
oauth2.AuthorizationCodeGrant restoreGrant(
CognitoOAuthConfig config, {
OAuthOutputs oauthOutputs,
String userPoolClientId, {
required String state,
required String codeVerifier,
http.Client? httpClient,
}) {
final grant = createGrant(
config,
oauthOutputs,
userPoolClientId,
codeVerifier: codeVerifier,
httpClient: httpClient,
);
Expand All @@ -192,7 +209,7 @@ abstract class HostedUiPlatform implements Closeable {
// Advances the internal state.
..getAuthorizationUrl(
signInRedirectUri,
scopes: config.scopes,
scopes: oauthOutputs.scopes,
state: state,
);
}
Expand Down Expand Up @@ -247,7 +264,8 @@ abstract class HostedUiPlatform implements Closeable {
final parameters = dependencyManager.get<OAuthParameters>();
if (parameters != null) {
authCodeGrant = restoreGrant(
config,
authOutputs.oauth!,
authOutputs.userPoolClientId!,
state: state,
codeVerifier: codeVerifier,
httpClient: httpClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import 'package:amplify_auth_cognito_dart/amplify_auth_cognito_dart.dart';
import 'package:amplify_auth_cognito_dart/src/flows/hosted_ui/hosted_ui_platform.dart';
import 'package:amplify_core/amplify_core.dart';
// ignore: implementation_imports
import 'package:aws_common/src/js/common.dart';
import 'package:path/path.dart' show url;
Expand Down Expand Up @@ -31,15 +30,19 @@ class HostedUiPlatformImpl extends HostedUiPlatform {
}

@override
Uri get signInRedirectUri => config.signInRedirectUris.firstWhere(
(uri) => uri.toString().startsWith(_baseUrl),
orElse: () => _noSuitableRedirect(signIn: true),
Uri get signInRedirectUri => Uri.parse(
authOutputs.oauth!.redirectSignInUri.firstWhere(
(uri) => uri.startsWith(_baseUrl),
orElse: () => _noSuitableRedirect(signIn: true),
),
);

@override
Uri get signOutRedirectUri => config.signOutRedirectUris.firstWhere(
(uri) => uri.toString().startsWith(_baseUrl),
orElse: () => _noSuitableRedirect(signIn: false),
Uri get signOutRedirectUri => Uri.parse(
authOutputs.oauth!.redirectSignOutUri.firstWhere(
(uri) => uri.startsWith(_baseUrl),
orElse: () => _noSuitableRedirect(signIn: false),
),
);

/// Launches the given URL.
Expand Down
Loading
Loading