diff --git a/CHANGELOG.md b/CHANGELOG.md index 834f017..906ced1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,126 +1,120 @@ -## 0.0.1 - -### Packages +## 2.1.0 -| Name | Description | -| ------------ | ----------------------------------------------------------------------------------------------------------- | -| logto_core | Core SDK is used for generation dart project with basic API and util method provided. | -| logto_client | Client SDK for flutter native apps. Built based on logto_core with user sign-in interaction flow integrated | +### New features -### Platforms +Add extra parameters to the signIn method for better sign-in experience customization. -iOS, Android +See the [Authentication parameters](https://docs.logto.io/docs/references/openid-connect/authentication-parameters) for more details. -### Features +1. `directSignIn`: This parameter allows you to skip the first screen of the sign-in page and directly go to the social or enterprise sso connectors's sign-in page. -- User sign-in using Logto's webAuth -- User sign-out -- Retrieve idToken claims -- Retrieve access token + - `social:`: Use the specified social connector, e.g. `social:google` + - `sso:`: Use the specified enterprise sso connector, e.g. `sso:123456` -## 1.0.0 +2. `firstScreen`: This parameter allows you to customize the first screen that users see when they start the authentication process. The value for this parameter can be: -### logto_client + - `sign_in`: Allow users to directly access the sign-in page. + - `register`: Allow users to directly access the registration page. + - `single_sign_on`: Allow users to directly access the single sign-on (SSO) page. + - `identifier:sign_in`: Allow users to direct access a page that only display specific identifier-based sign-in methods to users. + - `identifier:register`: Allow users to direct access a page that only display specific identifier-based registration methods to users. + - `reset_password`: Allow users to directly access the password reset page. -- Support RBAC -- Add `LogtoClient.getUserInfo` to get authenticated user info +3. `identifiers`: Additional parameter to specify the identifier type for the first screen. This parameter is only used when the `firstScreen` parameter is set to `identifier:sign_in`, `identifier:register` or `reset_password`. The value can be a list of the following supported identifier types: -## 1.1.0 + - `email` + - `phone` + - `username` -- fix Logto sign-out bug, the token revoke endpoint was misconfigured -- bump version to support Flutter 3.10 -- bump the http dependency to the latest version -- bump the flutter_web_auth dependency to the latest version -- bump the flutter_secure_storage dependency to the latest version +4. `extraParams`: This parameter allow you to pass additional custom parameters to the Logto sign-in page. The value for this parameter should be a Map object. -## 1.2.0 +### Bug fixes -### Dependencies update +Fix the `logtoClient.getAccessToken` method always fetching new access token bug. -- bump http package dependency to 1.2.0 -- bump flutter_secure_storage package dependency to 9.0.0 -- bump flutter_lints package dependency to 3.0.x +Background: +On each token exchange request, Logto dart SDK will cache the token response in the local storage. To reduce the number of token exchange requests, the SDK should always return the cached access token if it's not expired. Only when the access token is expired, the SDK should fetch a new access token using the refresh token. +However, the current implementation always fetches a new access token even if the cached access token is not expired. -### Features +Root cause: +Previously, all the access token storage keys are generated using the combination of the token's `resource`, `organization` and `scopes` values. This is to ensure that multiple access tokens can be stored in the storage without conflict. +Logto does not support narrowing down the scopes during a token exchange request, so the scopes value is always the same as the initial token request, therefore `scopes` is not necessary to be included in the `logtoClient.getAccessToken` method. Without the `scopes` value specified, the SDK can not locate the correct access token in the storage, which leads to always fetching a new access token. -- Update `LogtoConfig` to support new organization feature, including new organization scopes and fetching organization token -- Add `LogtoClient.getOrganizationToken` method to support organization token retrieval +Fix: +Remove the `scope` parameter from the `_tokenStorage.buildAccessTokenKey` and `_tokenStorage.getAccessToken` methods. Always get and set the access token using the `resource` and `organization` values as the key. -### Refactor +## 2.0.2 -- Export all the necessary classes and interfaces from `logto_core` to `logto_client` package -- Update the example app to demonstrate the new organization feature +### Bug fixes -## 2.0.0 +Fix the `OpenIdClaims` class key parsing issue: -Upgrade to dart 3.0.0 +- `avatar` key is now `picture` mapped from the `picture` key in the token claims +- `phone` key is now `phoneNumber` mapped from the `phone_number` key in the token claims +- `phoneVerified` key is now `phoneNumberVerified` mapped from the `phone_number_verified` key in the token claims -- Fix the `UserInfo` abstract class used as mixin incompatibility issue -- SDK now supports Dart ^3.0.0 -- < 3.0.0 users please use the previous version of the SDK +Previous key mapping values are always empty as they are not available in the IdToken claims. +This fix update the key mapping to the correct values. ## 2.0.1 -Bug fix +### Bug fixes Issue: `LogtoClient.getUserInfo` method throws an `not authenticated` error when the initial access token is expired. Expected behavior: The method should refresh the access token and return the user info properly. Fix: Always get the access token by calling `LogtoClient.getAccessToken`, which will refresh the token automatically if it's expired. -## 2.0.2 +## 2.0.0 -Bug fix +### Dependencies update -Fix the `OpenIdClaims` class key parsing issue: +Upgrade to dart 3.0.0 -- `avatar` key is now `picture` mapped from the `picture` key in the token claims -- `phone` key is now `phoneNumber` mapped from the `phone_number` key in the token claims -- `phoneVerified` key is now `phoneNumberVerified` mapped from the `phone_number_verified` key in the token claims +- Fix the `UserInfo` abstract class used as mixin incompatibility issue +- SDK now supports Dart ^3.0.0 +- < 3.0.0 users please use the previous version of the SDK -Previous key mapping values are always empty as they are not available in the IdToken claims. -This fix update the key mapping to the correct values. +## 1.2.0 -## 2.1.0 +### Dependencies update -### New Features +- bump http package dependency to 1.2.0 +- bump flutter_secure_storage package dependency to 9.0.0 +- bump flutter_lints package dependency to 3.0.x -Add extra parameters to the signIn method for better sign-in experience customization. +### New features -See the [Authentication parameters](https://docs.logto.io/docs/references/openid-connect/authentication-parameters) for more details. +- Update `LogtoConfig` to support new organization feature, including new organization scopes and fetching organization token +- Add `LogtoClient.getOrganizationToken` method to support organization token retrieval -1. `directSignIn`: This parameter allows you to skip the first screen of the sign-in page and directly go to the social or enterprise sso connectors's sign-in page. +### Refactors - - `social:`: Use the specified social connector, e.g. `social:google` - - `sso:`: Use the specified enterprise sso connector, e.g. `sso:123456` +- Export all the necessary classes and interfaces from `logto_core` to `logto_client` package +- Update the example app to demonstrate the new organization feature -2. `firstScreen`: This parameter allows you to customize the first screen that users see when they start the authentication process. The value for this parameter can be: +## 1.0.0 - - `sign_in`: Allow users to directly access the sign-in page. - - `register`: Allow users to directly access the registration page. - - `single_sign_on`: Allow users to directly access the single sign-on (SSO) page. - - `identifier:sign_in`: Allow users to direct access a page that only display specific identifier-based sign-in methods to users. - - `identifier:register`: Allow users to direct access a page that only display specific identifier-based registration methods to users. - - `reset_password`: Allow users to directly access the password reset page. +### New features -3. `identifiers`: Additional parameter to specify the identifier type for the first screen. This parameter is only used when the `firstScreen` parameter is set to `identifier:sign_in`, `identifier:register` or `reset_password`. The value can be a list of the following supported identifier types: +- Support RBAC +- Add `LogtoClient.getUserInfo` method to get authenticated user info - - `email` - - `phone` - - `username` +## 0.0.1 -4. `extraParams`: This parameter allow you to pass additional custom parameters to the Logto sign-in page. The value for this parameter should be a Map object. +### Packages -### Bug Fixes +| Name | Description | +| ------------ | ----------------------------------------------------------------------------------------------------------- | +| logto_core | Core SDK is used for generation dart project with basic API and util method provided. | +| logto_client | Client SDK for flutter native apps. Built based on logto_core with user sign-in interaction flow integrated | -Fix the `logtoClient.getAccessToken` method always fetching new access token bug. +### Supported Platforms -Background: -On each token exchange request, Logto dart SDK will cache the token response in the local storage. To reduce the number of token exchange requests, the SDK should always return the cached access token if it's not expired. Only when the access token is expired, the SDK should fetch a new access token using the refresh token. -However, the current implementation always fetches a new access token even if the cached access token is not expired. +iOS, Android -Root cause: -Previously, all the access token storage keys are generated using the combination of the token's `resource`, `organization` and `scopes` values. This is to ensure that multiple access tokens can be stored in the storage without conflict. -Logto does not support narrowing down the scopes during a token exchange request, so the scopes value is always the same as the initial token request, therefore `scopes` is not necessary to be included in the `logtoClient.getAccessToken` method. Without the `scopes` value specified, the SDK can not locate the correct access token in the storage, which leads to always fetching a new access token. +### Features -Fix: -Remove the `scope` parameter from the `_tokenStorage.buildAccessTokenKey` and `_tokenStorage.getAccessToken` methods. Always get and set the access token using the `resource` and `organization` values as the key. +- User sign-in using Logto's webAuth +- User sign-out +- Retrieve idToken claims +- Retrieve access token diff --git a/example/.gitignore b/example/.gitignore index 37da413..3fde43b 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related diff --git a/example/.metadata b/example/.metadata index 5df5c7a..8af9f15 100644 --- a/example/.metadata +++ b/example/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: f1875d570e39de09040c8f79aa13cc56baab8db1 - channel: stable + revision: "17025dd88227cd9532c33fa78f5250d548d87e9a" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 - base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 - - platform: ios - create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 - base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + - platform: android + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a # User provided section diff --git a/example/android/.gitignore b/example/android/.gitignore index 6f56801..55afd91 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -7,7 +7,7 @@ gradle-wrapper.jar GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index d94a1d2..b5511a9 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,71 +1,44 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { - compileSdkVersion 33 - ndkVersion flutter.ndkVersion + namespace = "com.example.example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" + applicationId = "com.example.example" // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion 19 - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig = signingConfigs.debug } } } flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + source = "../.." } diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 45d523a..399f698 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + - + - - - - - - - + + + + + + + - + + + + + + + + diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt index e793a00..70f8f08 100644 --- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -2,5 +2,4 @@ package com.example.example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { -} +class MainActivity: FlutterActivity() diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index 45d523a..399f698 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + - + @@ -31,28 +31,8 @@ example - - - - - + diff --git a/example/web/manifest.json b/example/web/manifest.json index 096edf8..d2c66a4 100644 --- a/example/web/manifest.json +++ b/example/web/manifest.json @@ -1,35 +1,35 @@ { - "name": "example", - "short_name": "example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] + "name": "example", + "short_name": "example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] } diff --git a/lib/logto_client.dart b/lib/logto_client.dart index b0dd8b8..88cbdf6 100644 --- a/lib/logto_client.dart +++ b/lib/logto_client.dart @@ -1,6 +1,8 @@ -import 'package:flutter_web_auth/flutter_web_auth.dart'; +import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:jose/jose.dart'; +import 'package:flutter_web_auth_2/flutter_web_auth_2.dart'; import '/src/exceptions/logto_auth_exceptions.dart'; import '/src/interfaces/logto_interfaces.dart'; @@ -8,9 +10,9 @@ import '/src/modules/id_token.dart'; import '/src/modules/logto_storage_strategy.dart'; import '/src/modules/pkce.dart'; import '/src/modules/token_storage.dart'; +import '/src/utilities/constants.dart'; import '/src/utilities/utils.dart' as utils; import 'logto_core.dart' as logto_core; -import '/src/utilities/constants.dart'; export '/src/exceptions/logto_auth_exceptions.dart'; export '/src/interfaces/logto_interfaces.dart'; @@ -229,10 +231,16 @@ class LogtoClient { final redirectUriScheme = Uri.parse(redirectUri).scheme; - final String callbackUri = await FlutterWebAuth.authenticate( + final String callbackUri = await FlutterWebAuth2.authenticate( url: signInUri.toString(), callbackUrlScheme: redirectUriScheme, - preferEphemeral: true, + options: const FlutterWebAuth2Options( + /// Prefer ephemeral web views for the sign-in flow. Only has an effect on Android. + intentFlags: ephemeralIntentFlags, + + /// Prefer ephemeral web views for the sign-in flow. Only has an effect on iOS. + preferEphemeral: true, + ), ); await _handleSignInCallback(callbackUri, redirectUri, httpClient); @@ -275,7 +283,7 @@ class LogtoClient { } // Sign out the user. - Future signOut() async { + Future signOut(String redirectUri) async { // Throw error is authentication status not found final idToken = await _tokenStorage.idToken; @@ -306,6 +314,24 @@ class LogtoClient { } await _tokenStorage.clear(); + + // Redirect to the end session endpoint it the platform is not iOS + // iOS uses the preferEphemeral flag on the sign-in flow, it will not preserve the session. + // For Android and Web, we need to redirect to the end session endpoint to clear the session manually. + if (kIsWeb || !Platform.isIOS) { + final signOutUri = logto_core.generateSignOutUri( + endSessionEndpoint: oidcConfig.endSessionEndpoint, + clientId: config.appId, + postLogoutRedirectUri: Uri.parse(redirectUri)); + final redirectUriScheme = Uri.parse(redirectUri).scheme; + + // Execute the sign-out flow asynchronously, this should not block the main app to render the UI. + await FlutterWebAuth2.authenticate( + url: signOutUri.toString(), + callbackUrlScheme: redirectUriScheme, + options: const FlutterWebAuth2Options( + intentFlags: ephemeralIntentFlags)); + } } finally { if (_httpClient == null) { httpClient.close(); diff --git a/lib/logto_dart_sdk.dart b/lib/logto_dart_sdk.dart index b4a2398..42064ec 100644 --- a/lib/logto_dart_sdk.dart +++ b/lib/logto_dart_sdk.dart @@ -1,4 +1,2 @@ -library logto_dart_sdk; - export 'logto_client.dart'; export 'logto_core.dart'; diff --git a/lib/src/interfaces/logto_code_token_response.g.dart b/lib/src/interfaces/logto_code_token_response.g.dart index f424578..5cc24a0 100644 --- a/lib/src/interfaces/logto_code_token_response.g.dart +++ b/lib/src/interfaces/logto_code_token_response.g.dart @@ -22,7 +22,7 @@ LogtoCodeTokenResponse _$LogtoCodeTokenResponseFromJson( accessToken: json['access_token'] as String, idToken: json['id_token'] as String, scope: json['scope'] as String, - expiresIn: json['expires_in'] as int, + expiresIn: (json['expires_in'] as num).toInt(), refreshToken: json['refresh_token'] as String?, ); } diff --git a/lib/src/interfaces/logto_refresh_token_response.g.dart b/lib/src/interfaces/logto_refresh_token_response.g.dart index f9f0127..a398ff8 100644 --- a/lib/src/interfaces/logto_refresh_token_response.g.dart +++ b/lib/src/interfaces/logto_refresh_token_response.g.dart @@ -17,7 +17,7 @@ LogtoRefreshTokenResponse _$LogtoRefreshTokenResponseFromJson( accessToken: json['access_token'] as String, refreshToken: json['refresh_token'] as String?, idToken: json['id_token'] as String?, - expiresIn: json['expires_in'] as int, + expiresIn: (json['expires_in'] as num).toInt(), scope: json['scope'] as String, ); } diff --git a/lib/src/interfaces/logto_user_info_response.dart b/lib/src/interfaces/logto_user_info_response.dart index e1ee48e..281ef49 100644 --- a/lib/src/interfaces/logto_user_info_response.dart +++ b/lib/src/interfaces/logto_user_info_response.dart @@ -25,6 +25,8 @@ class LogtoUserInfoResponse { final Map? customData; @JsonKey(name: 'identities') final Map? identities; + @JsonKey(name: 'roles') + final List? roles; @JsonKey(name: 'organizations') final List? organizations; @JsonKey(name: 'organization_roles') @@ -43,6 +45,7 @@ class LogtoUserInfoResponse { this.phoneNumberVerified, this.customData, this.identities, + this.roles, this.organizations, this.organizationRoles, this.organizationData, diff --git a/lib/src/interfaces/logto_user_info_response.g.dart b/lib/src/interfaces/logto_user_info_response.g.dart index 9312b98..403dc9e 100644 --- a/lib/src/interfaces/logto_user_info_response.g.dart +++ b/lib/src/interfaces/logto_user_info_response.g.dart @@ -24,6 +24,7 @@ LogtoUserInfoResponse _$LogtoUserInfoResponseFromJson( phoneNumberVerified: json['phone_number_verified'] as bool?, customData: json['custom_data'] as Map?, identities: json['identities'] as Map?, + roles: (json['roles'] as List?)?.map((e) => e as String).toList(), organizations: (json['organizations'] as List?) ?.map((e) => e as String) .toList(), @@ -37,28 +38,23 @@ LogtoUserInfoResponse _$LogtoUserInfoResponseFromJson( } Map _$LogtoUserInfoResponseToJson( - LogtoUserInfoResponse instance) { - final val = { - 'sub': instance.sub, - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('username', instance.username); - writeNotNull('name', instance.name); - writeNotNull('picture', instance.picture); - writeNotNull('email', instance.email); - writeNotNull('email_verified', instance.emailVerified); - writeNotNull('phone_number', instance.phoneNumber); - writeNotNull('phone_number_verified', instance.phoneNumberVerified); - writeNotNull('custom_data', instance.customData); - writeNotNull('identities', instance.identities); - writeNotNull('organizations', instance.organizations); - writeNotNull('organization_roles', instance.organizationRoles); - writeNotNull('organization_data', instance.organizationData); - return val; -} + LogtoUserInfoResponse instance) => + { + 'sub': instance.sub, + if (instance.username case final value?) 'username': value, + if (instance.name case final value?) 'name': value, + if (instance.picture case final value?) 'picture': value, + if (instance.email case final value?) 'email': value, + if (instance.emailVerified case final value?) 'email_verified': value, + if (instance.phoneNumber case final value?) 'phone_number': value, + if (instance.phoneNumberVerified case final value?) + 'phone_number_verified': value, + if (instance.customData case final value?) 'custom_data': value, + if (instance.identities case final value?) 'identities': value, + if (instance.roles case final value?) 'roles': value, + if (instance.organizations case final value?) 'organizations': value, + if (instance.organizationRoles case final value?) + 'organization_roles': value, + if (instance.organizationData case final value?) + 'organization_data': value, + }; diff --git a/lib/src/interfaces/openid.dart b/lib/src/interfaces/openid.dart index 1286a5e..f07a075 100644 --- a/lib/src/interfaces/openid.dart +++ b/lib/src/interfaces/openid.dart @@ -10,8 +10,6 @@ extension LogtoReservedResourceExtension on LogtoReservedResource { switch (this) { case LogtoReservedResource.organization: return 'urn:logto:resource:organizations'; - default: - throw Exception("Invalid value"); } } } @@ -60,8 +58,6 @@ extension LogtoUserScopeUserScopeExtension on LogtoUserScope { return 'urn:logto:scope:organizations'; case LogtoUserScope.organizationRoles: return 'urn:logto:scope:organization_roles'; - default: - throw Exception("Invalid value"); } } } diff --git a/lib/src/utilities/constants.dart b/lib/src/utilities/constants.dart index c81f192..167eec3 100644 --- a/lib/src/utilities/constants.dart +++ b/lib/src/utilities/constants.dart @@ -43,8 +43,6 @@ extension InteractionModeExtension on InteractionMode { return 'signIn'; case InteractionMode.signUp: return 'signUp'; - default: - throw Exception("Invalid value"); } } } @@ -78,8 +76,6 @@ extension FirstScreenExtension on FirstScreen { return 'identifier:register'; case FirstScreen.singleSignOn: return 'single_sign_on'; - default: - throw Exception("Invalid value"); } } } @@ -104,8 +100,6 @@ extension IdentifierTypeExtension on IdentifierType { return 'phone'; case IdentifierType.username: return 'username'; - default: - throw Exception("Invalid value"); } } } diff --git a/pubspec.yaml b/pubspec.yaml index 1db1d4b..1c1262e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,31 +1,30 @@ name: logto_dart_sdk description: Logto's Flutter SDK packages. -version: 2.1.0 +version: 3.0.0 homepage: https://github.com/logto-io/dart documentation: https://docs.logto.io/sdk/flutter/ environment: - sdk: ">=3.0.0 <4.0.0" + sdk: "^3.6.0" flutter: ">=1.17.0" dependencies: - crypto: ^3.0.2 + crypto: ^3.0.6 flutter: sdk: flutter flutter_secure_storage: ^9.0.0 http: ^1.2.0 - jose: ^0.3.2 - json_annotation: ^4.6.0 + jose: ^0.3.4 + json_annotation: ^4.9.0 path: ^1.8.1 - flutter_web_auth: ^0.6.0 - collection: ^1.17.1 + flutter_web_auth_2: ^4.1.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^5.0.0 - json_serializable: ^6.3.1 - build_runner: ^2.2.0 + json_serializable: ^6.9.3 + build_runner: ^2.4.14 nock: ^1.2.1 # For information on the generic Dart part of this file, see the