0% found this document useful (0 votes)
29 views10 pages

SSO 2.0 - Flutter SDK

The document outlines the implementation of Single Sign-On (SSO) for Flutter applications, allowing users to access multiple services with a single login. It details installation steps for the SSO library, integration procedures, and handling user verification for required fields like email and phone. Additionally, it provides guidelines for social login integration with Google, Facebook, and Apple, along with necessary configurations and code examples.

Uploaded by

sudhirdengre
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views10 pages

SSO 2.0 - Flutter SDK

The document outlines the implementation of Single Sign-On (SSO) for Flutter applications, allowing users to access multiple services with a single login. It details installation steps for the SSO library, integration procedures, and handling user verification for required fields like email and phone. Additionally, it provides guidelines for social login integration with Google, Facebook, and Apple, along with necessary configurations and code examples.

Uploaded by

sudhirdengre
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

SSO Flutter (Flutter Version Support From 3.24.

4)
Single Sign-On (SSO) is an authentication process that allows a user to access multiple Manorama applications or
services with one set of login credentials. This means that after logging in once, the user can access all interconnected
systems without needing to log in separately for each one. Additionally, we are implementing login options via Facebook,
Apple, and Google.

Note:
1. Since the git repo is private, the access to import the repo will be granted on request by sharing the client developer
device’s SSH key pair with the SSO app development team

Installation
open your pubspec.yaml file and add the library under the dependencies section. Here’s an example:

Install a library via SSH

1 sso_hifx:
2 git:
3 url: [email protected]:mm-shamar/sso-flutter.git
4 ref: 1.0.7

Install a library via HTTP

1 sso_hifx:
2 git:
3 url: http://git.hifx.in/mm-shamar/sso-flutter.git
4 ref: 1.0.7

You can install the library using either of the two methods: via SSH or HTTP.

Integration Steps
To implement Single Sign-On (SSO) in your application, follow these steps to create a configuration file and manage the
integration process:

1. Create your Android/IOS client in SSO admin panel


2. Create a configuration file that will store necessary settings for your SSO implementation. This file includes
parameters like client ID, redirect URL etc..
3. Download configuration file and add your client details configuration.json
4. Add this configuration file into your assets path
5. Call SSO init in to your main class

1 void main() async {


2 WidgetsFlutterBinding.ensureInitialized();
3 await SSOConfig().init(
4 configurationPath: 'assets/configuration.json',
5 );
6 runApp(const MyApp());
7 }

6. Create a stateful or stateless widget and call the SSO SDK; the AuthListener class should be implemented in this class.
1 import 'package:sso_hifx/interface/auth_listener.dart';
2 import 'package:sso_hifx/model/login/user.dart';
3 import 'package:sso_hifx/sso_hifx.dart';
4 class SSO extends StatefulWidget {
5 const SSO({super.key});
6 @override
7 State<SSO> createState() => _SSOState();
8 }
9 class _SSOState extends State<SSO> implements AuthListener {
10 @override
11 Widget build(BuildContext context) {
12 return SSO(authListener: this);
13 }
14 @override
15 onSuccessLogin(User user) {
16 SnackBarUtils.showSuccessSnackBar(context, user.accessToken);
17 }
18 @override
19 onUserVerifiedPostLogin(String idToken) async {
20 }
21 }

7. When the login is successful, the onSuccessLogin function will trigger, allowing you to navigate to any desired page.
8. onUserVerifiedPostLogin will be triggered when the required field (email, phone, or name) is verified.

In an SSO scenario, users can log in using either their email or mobile number. For example, if a user logs in using
their mobile number but our main project requires an email, the system will redirect them to provide and verify their
email. Once verified, the onUserVerifiedPostLogin will be triggered.

Similarly, The name field is optional and the project requires a name, the user will be redirected to the name creation
page. Once the name is provided, onUserVerifiedPostLogin will be triggered.
9. If your project requires verification of email, mobile, or name, you need to handle this in your main project. After a
successful login callback, you should check whether the required fields are verified. Below is an example for reference:

10. 1 import 'package:flutter/material.dart';


2 import 'package:flutter_riverpod/flutter_riverpod.dart';
3 import 'package:hello_address/application/sso/sso_notifier.dart';
4 import 'package:hello_address/core/routes.dart';
5 import 'package:hello_address/domain/sso/model/sso_arguments.dart';
6 import 'package:hello_address/presentation/sso/widgets/verify_loader.dart';
7 import 'package:sso_hifx/core/sso_services.dart';
8 import 'package:sso_hifx/interface/auth_listener.dart';
9 import 'package:sso_hifx/model/login/user.dart';
10 import 'package:sso_hifx/sso_hifx.dart';
11 import '../../core/app_storage.dart';
12 /// Showing SSO SSOLogin page
13 class SSOView extends ConsumerStatefulWidget {
14 const SSOView({super.key});
15 @override
16 ConsumerState<SSOView> createState() => _SSOState();
17 }
18 class _SSOState extends ConsumerState<SSOView> implements AuthListener {
19 late SSOArguments ssoArguments;
20 @override
21 void didChangeDependencies() {
22 super.didChangeDependencies();
23 if (ModalRoute.of(context)!.settings.arguments != null) {
24 ssoArguments = ModalRoute.of(context)!.settings.arguments as SSOArguments;
25 }
26 }
27 @override
28 Widget build(BuildContext context) {
29 final ssoNotifier = ref.watch(ssoNotifierProvider);
30 return PopScope(
31 child: Scaffold(
32 body: Stack(
33 alignment: Alignment.center,
34 children: [
35 SSO(
36 authListener: this,
37 requiredFields: ssoArguments.requiredFields,
38 ),
39 if (ssoNotifier.isLoading) const Positioned(child: VerifyLoader())
40 ],
41 ),
42 ),
43 );
44 }
45 @override
46 onSuccessLogin(User user) async {
47 if (mounted) {
48 final userInfo = await SSOServices().getUserInfo();
49 if (userInfo != null) {
50 // Collect unverified or missing required fields
51 final List<String> requiredFields = [
52 if (!userInfo.emailVerified) "email",
53 if (userInfo.name.isEmpty) "name",
54 if (!userInfo.mobileVerified) "phone",
55 ];
56 if (requiredFields.isNotEmpty) {
57 AppStorage().setLogin(false);
58 if (mounted) {
59 Navigator.pushNamedAndRemoveUntil(
60 context,
61 Routes.sso,
62 arguments: SSOArguments(
63 isCallRequirementApi: false,
64 from: ssoArguments.from,
65 requiredFields: requiredFields,
66 propertyDetailArguments:
67 ssoArguments.propertyDetailArguments),
68 (route) => route.settings.name == Routes.dashboard,
69 );
70 }
71 } else {
72 if (mounted) {
73 ref.read(ssoNotifierProvider.notifier).ssoAuthenticate(context,
74 idToken: user.idToken, ssoArguments: ssoArguments);
75 if (user.isLoggedFromVerification ||
76 user.isLoggedFromSocialLoginOnCreateAccountPage ||
77 user.isLoggedFromSocialLoginOnOTPPage ||
78 user.isLoggedFromOTPPage) {
79 Navigator.pushReplacementNamed(context, Routes.sso,
80 arguments: SSOArguments(
81 isCallRequirementApi: false,
82 from: ssoArguments.from,
83 propertyDetailArguments:
84 ssoArguments.propertyDetailArguments));
85 }
86 }
87 }
88 }
89 }
90 }
91 @override
92 onUserVerifiedPostLogin(String idToken) async {
93 if (mounted) {
94 ref.read(ssoNotifierProvider.notifier).ssoAuthenticate(context,
95 idToken: idToken, ssoArguments: ssoArguments);
96 Navigator.pushReplacementNamed(context, Routes.sso,
97 arguments: SSOArguments(
98 isCallRequirementApi: false,
99 from: ssoArguments.from,
100 propertyDetailArguments: ssoArguments.propertyDetailArguments));
101 }
102 }
103 }
104

Note:

Workflow for Handling Navigation with SSO Integration

When handling the login success callback, you need to use pushNamedAndRemoveUntil to navigate and set the desired
route in the back stack. This must be managed within the project because the SSO library utilizes direct navigation, which
does not support named navigation.

Using named navigation within the SSO library would result in the removal of project routes from the navigation stack.
Additionally, the SSO library does not allow calling pushNamedAndRemoveUntil directly.

Therefore, it is essential to handle this navigation logic within your project. This approach has been successfully
implemented in the Hello Address project.

Explanation of the Code and Workflow

In the provided example, the SSOView widget manages the Single Sign-On (SSO) login process. It ensures that all the
required fields (like email, name, or phone) are verified before proceeding. Below is a breakdown of the key sections and
their purposes:

1. onSuccessLogin Callback

Purpose: Triggered after a successful login. The function checks whether all required fields (email, name, or phone)
are verified.
Workflow:
Unverified Fields Handling: If required fields are missing (e.g., email, name, phone), the app:
i. Redirects back to the SSO page ( Routes.sso ) with the missing required fields passed in SSOArguments .
Verified Fields Handling: If all required fields are verified:
If your project includes an external API call After SSO Login, you can implement it and display a verification
loader. If there is no external API call, you can directly redirect to the desired screen.
Special Cases: If the user is logged in through one of the flags ( isLoggedFromVerification ,
isLoggedFromSocialLoginOnCreateAccountPage , isLoggedFromSocialLoginOnOTPPag,isLoggedFromOTPPage .), the app
redirects to the SSO page again to finalize the flow.
2. onUserVerifiedPostLogin Callback

Purpose: Triggered once the user verifies any required fields after login.
Workflow:
If your project includes an external API call After SSO Login, you can implement it and display a verification loader.
If there is no external API call, you can directly redirect to the desired screen
Redirects to the SSO page to ensure a consistent flow and finalize authentication.

3. Why Redirect to SSO Page?

The app ensures that the SSO page is the central point of access for authentication and verification. This
consistency:

Prevents unauthorized access to other parts of the app.


Standardizes the user flow for handling verification and login.

For both onSuccessLogin and onUserVerifiedPostLogin :

If required fields are missing, the flow redirects to the SSO page to complete verification.

Workflow for Editing the Name with SSO Integration


1. Reloading the SSO Page:
To edit the name, you must reload the SSO page.
2. Passing Parameters:
Ensure that you pass the following parameters when reloading the SSO page:
UserListener : A listener for handling callbacks.

isEditEmail : A flag indicating whether the email edit functionality is enabled.

3. Implementing the UserListener Class:


Wherever you want to enable name editing, you need to implement the UserListener class. This will provide a
callback to handle the updated name or related actions.
4. Example Implementation:
Below is an example demonstrating how to implement the UserListener class:

1 class UserName extends StatefulWidget {


2 const UserName({
3 super.key,
4 required this.user,
5 required this.ref,
6 });
7 final User? user;
8 final WidgetRef ref;
9 @override
10 State<UserName> createState() => _UserNameState();
11 }
12 class _UserNameState extends State<UserName> implements UserListener {
13 @override
14 Widget build(BuildContext context) {
15 return CustomRichText(
16 text1: widget.user?.userFullName ?? "",
17 text2: " Edit Name?",
18 text1Size: FS.font17.val.spMin,
19 text2Size: FS.font13.val.spMin,
20 text1FontWeight: FontWeight.w500,
21 text2FontWeight: FontWeight.w600,
22 text1Color: AppColor.black.val,
23 text2Color: AppColor.primary.val,
24 textAlign: TextAlign.start,
25 onTapText2: () {
26 Navigator.pushNamed(context, Routes.sso,
27 arguments: SSOArguments(
28 isCallRequirementApi: false,
29 from: "Edit Profile",
30 isEditName: true,
31 userListener: this));
32 },
33 );
34 }
35 @override
36 onUserUpdated() {
37 // here you can reload the page
38 }
39 }

1 /// Showing SSO SSOLogin page


2 class SSOView extends ConsumerStatefulWidget {
3 const SSOView({super.key});
4 @override
5 ConsumerState<SSOView> createState() => _SSOState();
6 }
7 class _SSOState extends ConsumerState<SSOView> implements AuthListener {
8 late SSOArguments ssoArguments;
9 @override
10 void didChangeDependencies() {
11 super.didChangeDependencies();
12 if (ModalRoute.of(context)!.settings.arguments != null) {
13 ssoArguments = ModalRoute.of(context)!.settings.arguments as SSOArguments;
14 }
15 }
16 @override
17 Widget build(BuildContext context) {
18 final ssoNotifier = ref.watch(ssoNotifierProvider);
19 return PopScope(
20 canPop: !ssoNotifier.isLoading,
21 child: Scaffold(
22 body: Stack(
23 alignment: Alignment.center,
24 children: [
25 SSO(
26 authListener: this,
27 requiredFields: ssoArguments.requiredFields,
28 userListener: ssoArguments.userListener,
29 isEditName: ssoArguments.isEditName,
30 ),
31 if (ssoNotifier.isLoading) const Positioned(child: VerifyLoader())
32 ],
33 ),
34 ),
35 );
36 }
37 @override
38 onSuccessLogin(User user) async {
39 }
40 @override
41 onUserVerifiedPostLogin(String idToken) async {
42 }
43 reloadSSOWithAddBackStack(List<String> requiredFields) {
44 }

Social Login Steps


Google Login Android :

Go to https://console.cloud.google.com/cloud-resource-manager and create your Android and Web client.after that go to


your project android/app/src/main/res/strings.xml and add your web client id.

1 <?xml version="1.0" encoding="utf-8"?>


2 <resources>
3 <string name="default_web_client_id">{your-web-client-id}</string>
4 </resources>

To authenticate using the backend, you need to pass the ID token. If you don’t define the web client ID, you won’t receive
the ID token.
Google Login IOS:

Go to https://console.cloud.google.com/cloud-resource-manager and create your iOS and Web client(there is no need to


create the web client again if you have already done so.) and download Google-Service-Info.plist file.

After opening your project in Xcode, locate your GoogleService-Info.plist file. Copy the reverse client ID from there and
paste it into the Info.plist file.

1 <array>
2 <dict>
3 <key>CFBundleTypeRole</key>
4 <string>Editor</string>
5 <key>CFBundleURLSchemes</key>
6 <array>
7 <string>"your reverse client-id"</string>
8 </array>
9 </dict>
10 </array>

note :If you don’t add the reverse client id , the iOS application will crash.

facebook login:

Full documentation 👉 https://facebook.meedu.app


Apple login:

Go to your apple developer account add sign with apple entitlement.after that install the certificate and open the project
in Xcode and add sign with apple capability.

Methods
Get Login status

1 bool isLoggedIn = SSOServices().isSSoLoggedIn();


2 Logger.log(msg: "isLogin $isLoggedIn");

Get ID Token

1 String idToken = await SSOServices().getIdToken();


2 Logger.log(msg: "Id token is $idToken");

Get Access Token

1 String accessToken = await SSOServices().getAccessToken();


2 Logger.log(msg: "Access token is $accessToken");

Get Refresh token

1 String refreshToken = SSOServices().getRefreshToken();


2 Logger.log(msg: "refresh token is $refreshToken");

Get User info

1 UserInfo? info = await SSOServices().getUserInfo();


2 Logger.log(msg:"user info ${json.encode(info)}${info?.ssoUserId} ${info?.email}");

Token Refresh

To refresh the token in your application, you make the call as follows

1 final tokenRefresh = await SSOServices().tokenRefresh();


2 Logger.log(msg: "Token refresh ${tokenRefresh?.accessToken} and ${tokenRefresh?.idToken}");

Force Token Refresh

To forcefully refresh the token in your application, you make the call as follows:

1 final forceRefreshToken = await SSOServices().forceTokenRefresh();


2 Logger.log(msg: "forceRefreshToken ${forceRefreshToken?.idToken} and ${forceRefreshToken?.accessToken}");

SSO Delete account

To delete SSO account, you make the call as follows:

1 DeleteUser user =await SSOServices().deleteAccount();


2 if(user.isErrorInDeletion){
3 Logger.log(msg: user.message);
4 }else{
5 Logger.log(msg: user.message);
6 }

Conclusion
By following these installation steps, you can seamlessly integrate SSOKit into your Flutter project and leverage its
powerful features to implement single sign-on functionality in your Flutter applications.

You might also like