Skip to main content

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')),
),
);
}
}
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