Flutter SDK
Complete guide to integrating Signia authentication in Flutter applications.
Installation
Add to your pubspec.yaml:
dependencies:
signia_auth_sdk: ^0.1.0
signia_auth_ui_flutter: ^0.1.0
Then run:
flutter pub get
Setup
1. Initialize OIDC Client
Create the OIDC client with your configuration:
import 'package:signia_auth_sdk/signia_auth_sdk.dart';
final oidcClient = OIDCClient(
clientId: 'YOUR_CLIENT_ID',
redirectUri: 'myapp://oidc-callback',
issuer: 'https://YOUR_TENANT.signiaauth.com',
scopes: ['openid', 'profile', 'email'],
);
2. Configure Deep Linking
iOS (ios/Runner/Info.plist)
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Android (android/app/src/main/AndroidManifest.xml)
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
3. Add Provider
Wrap your app with SigniaAuthProvider:
import 'package:flutter/material.dart';
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
void main() {
runApp(
SigniaAuthProvider(
client: oidcClient,
child: MyApp(),
),
);
}
Widgets
SigniaAuthConsumer
Access authentication state:
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class ProfileScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SigniaAuthConsumer(
builder: (context, authState) {
if (authState.isLoading) {
return Center(child: CircularProgressIndicator());
}
if (authState.error != null) {
return Center(child: Text('Error: ${authState.error}'));
}
if (!authState.isAuthenticated) {
return Center(child: Text('Please log in'));
}
final user = authState.user;
return Column(
children: [
Text('Welcome ${user?.email}'),
Text('User ID: ${user?.sub}'),
],
);
},
);
}
}
LoginButton
Pre-built login button:
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Welcome to My App'),
SizedBox(height: 20),
LoginButton(),
// Or customize:
LoginButton(
child: Text('Sign In'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
),
),
],
),
),
);
}
}
LogoutButton
Pre-built logout button:
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Settings')),
body: Center(
child: LogoutButton(),
),
);
}
}
ProtectedRoute
Protect routes that require authentication:
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class DashboardScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ProtectedRoute(
loadingWidget: Center(child: CircularProgressIndicator()),
child: Scaffold(
appBar: AppBar(title: Text('Dashboard')),
body: Center(child: Text('Protected Content')),
),
);
}
}
Navigation Integration
import 'package:flutter/material.dart';
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Signia Demo',
home: SigniaAuthConsumer(
builder: (context, authState) {
if (authState.isLoading) {
return Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
if (authState.isAuthenticated) {
return HomeScreen();
}
return LoginScreen();
},
),
);
}
}
Advanced Usage
Manual Authentication
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class CustomLoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final authProvider = SigniaAuth.of(context);
return ElevatedButton(
onPressed: () async {
try {
await authProvider.login();
} catch (e) {
print('Login failed: $e');
}
},
child: Text('Login'),
);
}
}
Authenticated API Calls
import 'package:http/http.dart' as http;
class UserDataScreen extends StatefulWidget {
@override
_UserDataScreenState createState() => _UserDataScreenState();
}
class _UserDataScreenState extends State<UserDataScreen> {
Map<String, dynamic>? userData;
@override
void initState() {
super.initState();
fetchUserData();
}
Future<void> fetchUserData() async {
final authProvider = SigniaAuth.of(context);
final httpClient = await authProvider.getAuthHttpClient();
final response = await httpClient.get(
Uri.parse('https://api.example.com/user'),
);
if (response.statusCode == 200) {
setState(() {
userData = jsonDecode(response.body);
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: userData != null
? Text(jsonEncode(userData))
: CircularProgressIndicator(),
);
}
}
State Management
Using Provider
import 'package:provider/provider.dart';
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SigniaAuthProvider(
client: oidcClient,
child: MaterialApp(
home: Consumer<SigniaAuthState>(
builder: (context, authState, child) {
if (authState.isAuthenticated) {
return HomeScreen();
}
return LoginScreen();
},
),
),
);
}
}
Using Bloc
import 'package:flutter_bloc/flutter_bloc.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
final OIDCClient client;
AuthBloc(this.client) : super(AuthInitial()) {
on<LoginRequested>((event, emit) async {
emit(AuthLoading());
try {
await client.login();
emit(AuthAuthenticated());
} catch (e) {
emit(AuthError(e.toString()));
}
});
}
}
Biometric Authentication
Signia supports biometric authentication on Flutter:
iOS
- Face ID
- Touch ID
Android
- Fingerprint
- Face unlock
No additional configuration needed beyond the standard biometric permissions.
Add Permissions
iOS (Info.plist):
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to securely authenticate you</string>
Android (AndroidManifest.xml):
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
Error Handling
SigniaAuthConsumer(
builder: (context, authState) {
if (authState.error != null) {
return ErrorWidget(
error: authState.error!,
onRetry: () {
SigniaAuth.of(context).login();
},
);
}
// ... rest of your UI
},
)
Troubleshooting
"Unable to launch URL" error
Make sure your deep linking scheme matches your configuration:
// ✅ Correct
redirectUri: 'myapp://oidc-callback'
// ❌ Wrong
redirectUri: 'http://localhost/callback'
Biometric authentication not available
Check if the device supports biometrics:
import 'package:local_auth/local_auth.dart';
final auth = LocalAuthentication();
final canCheckBiometrics = await auth.canCheckBiometrics;
final availableBiometrics = await auth.getAvailableBiometrics();
iOS build fails
Make sure you have the minimum deployment target:
# ios/Podfile
platform :ios, '14.0'
Complete Example
import 'package:flutter/material.dart';
import 'package:signia_auth_sdk/signia_auth_sdk.dart';
import 'package:signia_auth_ui_flutter/signia_auth_ui_flutter.dart';
final oidcClient = OIDCClient(
clientId: 'YOUR_CLIENT_ID',
redirectUri: 'myapp://oidc-callback',
issuer: 'https://YOUR_TENANT.signiaauth.com',
scopes: ['openid', 'profile', 'email'],
);
void main() {
runApp(
SigniaAuthProvider(
client: oidcClient,
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Signia Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: SigniaAuthConsumer(
builder: (context, authState) {
if (authState.isLoading) {
return Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
if (authState.isAuthenticated) {
return HomeScreen();
}
return LoginScreen();
},
),
);
}
}
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Welcome to My App',
style: Theme.of(context).textTheme.headlineMedium,
),
SizedBox(height: 40),
LoginButton(),
],
),
),
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
actions: [LogoutButton()],
),
body: SigniaAuthConsumer(
builder: (context, authState) {
final user = authState.user;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Welcome ${user?.name ?? user?.email}',
style: Theme.of(context).textTheme.headlineSmall,
),
SizedBox(height: 20),
Text('User ID: ${user?.sub}'),
SizedBox(height: 10),
Text('Email: ${user?.email}'),
],
),
);
},
),
);
}
}
Next Steps
- Core Concepts - Understand OIDC and Signia
- React SDK - Web integration reference