medha_auth 1.0.4
medha_auth: ^1.0.4 copied to clipboard
A Flutter authentication library for SSO integration with Microsoft authentication
Medha Auth #
A Flutter authentication library for Medha SSO integration with Microsoft authentication.
Features #
- WebView-based Microsoft SSO authentication
- Custom URL scheme redirects for mobile apps
- Secure token storage with flutter_secure_storage
- Automatic token refresh
- State management with streams
- Support for QA and Production environments
Prerequisites #
- Flutter SDK 3.0.0+
- Android minSdkVersion 21+
- iOS 12.0+
Installation #
dependencies:
medha_auth: ^1.0.1
app_links: ^6.1.1
rxdart: ^0.28.0
flutter_dotenv: ^5.1.0
flutter pub get
Quick Setup #
1. Environment Configuration #
Create .env in project root:
ENVIRONMENT=QA
SSO_BASE_URL_QA=https://your-sso-qa.example.com:3000
SSO_BACKEND_URL_QA=https://your-sso-api-qa.example.com:4000
SSO_BASE_URL_PROD=https://your-sso.example.com:3000
SSO_BACKEND_URL_PROD=https://your-sso-api.example.com:4000
SSO_CUSTOM_SCHEME=yourappauth
SSO_APPLICATION_NAME=YourAppName
Add to pubspec.yaml:
flutter:
assets:
- .env
Add to .gitignore:
.env
2. Initialize in main.dart #
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:medha_auth/medha_auth.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: ".env");
NavigationService.setNavigatorKey(navigatorKey);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
home: const LoginScreen(),
);
}
}
3. Platform Configuration #
iOS - Add to ios/Runner/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yourappauth</string>
</array>
</dict>
</array>
Android - Add to android/app/src/main/AndroidManifest.xml:
<activity android:name=".MainActivity" android:launchMode="singleTop">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourappauth" android:host="callback" />
</intent-filter>
</activity>
Create android/app/src/main/res/xml/network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">your-api-domain.com</domain>
<trust-anchors>
<certificates src="system"/>
</trust-anchors>
</domain-config>
</network-security-config>
Reference in AndroidManifest.xml <application> tag:
<application android:networkSecurityConfig="@xml/network_security_config">
4. Auth Configuration #
Create lib/config/auth_constants.dart:
import 'package:medha_auth/medha_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
class AuthConstants {
static AuthConfig get authConfig {
final isProduction = (dotenv.env['ENVIRONMENT'] ?? 'QA').toUpperCase() == 'PROD';
return AuthConfig(
ssoBaseUrl: isProduction
? dotenv.env['SSO_BASE_URL_PROD']!
: dotenv.env['SSO_BASE_URL_QA']!,
backendBaseUrl: isProduction
? dotenv.env['SSO_BACKEND_URL_PROD']!
: dotenv.env['SSO_BACKEND_URL_QA']!,
applicationName: dotenv.env['SSO_APPLICATION_NAME'] ?? 'MedhaAnalytics',
customScheme: dotenv.env['SSO_CUSTOM_SCHEME'] ?? 'medhaauth',
);
}
}
Usage #
Initialize and Login #
import 'package:medha_auth/medha_auth.dart';
import 'config/auth_constants.dart';
final authClient = AuthClient(config: AuthConstants.authConfig);
await authClient.initialize();
// Login
await authClient.login();
// Get tokens
final tokens = await authClient.getValidTokens();
// Logout
await authClient.logout();
Authentication State #
StreamBuilder<AuthState>(
stream: authClient.state,
builder: (context, snapshot) {
final state = snapshot.data ?? const AuthState.unknown();
return state.when(
authenticated: (tokens, userInfo) => HomeScreen(),
unauthenticated: (error) => LoginScreen(),
loading: () => CircularProgressIndicator(),
unknown: () => CircularProgressIndicator(),
refreshing: (tokens) => CircularProgressIndicator(),
);
},
);
Use Tokens in API Calls #
final tokens = await authClient.getValidTokens();
if (tokens != null) {
final response = await http.get(
Uri.parse('https://api.example.com/data'),
headers: {'Authorization': 'Bearer ${tokens.accessToken}'},
);
}
Configuration Options #
AuthConfig Parameters #
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ssoBaseUrl |
String | Yes | - | SSO authentication server URL |
backendBaseUrl |
String | Yes | - | Backend API URL for token operations |
applicationName |
String | Yes | - | Application name sent to SSO server |
customScheme |
String | No | 'medhaauth' |
Custom URL scheme for deep linking |
tokenRefreshThreshold |
Duration | No | Duration(minutes: 5) |
Time before expiry to trigger refresh |
requestTimeout |
Duration | No | Duration(seconds: 30) |
HTTP request timeout |
Example Configurations #
// Recommended: Load from environment variables
AuthClient(
config: AuthConfig(
ssoBaseUrl: dotenv.env['SSO_BASE_URL']!,
backendBaseUrl: dotenv.env['SSO_BACKEND_URL']!,
applicationName: dotenv.env['SSO_APPLICATION_NAME']!,
customScheme: dotenv.env['SSO_CUSTOM_SCHEME'] ?? 'medhaauth',
),
)
// Direct configuration (for testing/demo)
AuthClient(
config: AuthConfig(
ssoBaseUrl: 'https://your-sso.example.com:3000',
backendBaseUrl: 'https://your-backend.example.com:4000',
applicationName: 'MyApp',
customScheme: 'myapp',
),
)
Error Handling #
try {
await authClient.login();
} on AuthTimeoutException {
// Handle timeout
} on AuthCancelledException {
// Handle user cancellation
} on AuthException catch (e) {
// Handle other errors
}
Exception Types:
AuthException- General errorsAuthTimeoutException- TimeoutAuthCancelledException- User cancelledAuthRedirectException- Redirect errorsAuthTokenException- Token errors
Testing Deep Links #
Android:
adb shell am start -a android.intent.action.VIEW -d "yourappauth://callback"
iOS:
xcrun simctl openurl booted "yourappauth://callback"
Troubleshooting #
Login Hangs #
- Verify deep link configured in AndroidManifest/Info.plist
- Ensure custom scheme matches everywhere
- Check
network_security_config.xml
Network Errors #
- Add API domain to
network_security_config.xml - Verify HTTPS endpoints
- Check connectivity
Token Issues #
flutter clean
flutter pub get
flutter run
Best Practices #
Security:
- Never commit
.envfiles - Use HTTPS only
- Validate tokens before use
Performance:
- Initialize AuthClient once
- Dispose properly in widget lifecycle
- Use StreamBuilder for state updates
UX:
- Show loading indicators
- Handle errors gracefully
- Provide logout option
- Auto-login with valid tokens
Advanced Example #
class ProtectedScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<AuthState>(
stream: authClient.state,
builder: (context, snapshot) {
final state = snapshot.data ?? const AuthState.unknown();
return state.when(
authenticated: (tokens, userInfo) => Scaffold(
appBar: AppBar(title: Text('Welcome ${userInfo.name}')),
body: Center(child: Text('Protected Content')),
),
unauthenticated: (_) => LoginScreen(),
unknown: () => CircularProgressIndicator(),
loading: () => CircularProgressIndicator(),
refreshing: (_) => CircularProgressIndicator(),
);
},
);
}
}
Documentation #
For detailed integration guide, see INTEGRATION_GUIDE.md
Version #
1.0.1 - 2026-01-06
License #
Private - Medha Analytics