This package provides developers with an easy way to manage sessions and securely store public-private key pairs on iOS and Android devices. It is meant to be used with Turnkey's other Flutter packages to create a fully functional app powered by Turnkey. Key pairs are stored on device using the flutter_secure_storage package.
It is highly recommended to use the provider package and instantiate the SessionProvider class as a provider.
First, add the provider
package to your pubspec.yaml
:
dependencies:
provider: ^6.1.2
Then, wrap your app with the MultiProvider and add the SessionProvider:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:turnkey_sessions/turnkey_sessions.dart';
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => SessionProvider()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
You can now access the SessionProvider in your widgets and call its functions:
// your existing code...
@override
Widget build(BuildContext context) {
final sessionProvider = Provider.of<SessionProvider>(context);
// Create a P-256 public-private key pair (saves private key in secure storage)
final publicKey = await sessionProvider.createEmbeddedKey();
// Get private key from secure storage
final privateKey = await sessionProvider.getEmbeddedKey(deleteKey: true); // Optional deleteKey param
// Create a session using a credential bundle (retrieved from a Turnkey request)
await sessionProvider.createSession(credentialBundle);
// Access the session object
final session = await sessionProvider.getSession();
// Add a listener to the session provider. someFunction() will run when the session is updated
sessionProvider.addListener(someFunction());
// rest of your code...
}
Here is an example of authenticating a user with Turnkey using a passkey. This function leverages Turnkey's Flutter passkey stamper and http client. A session is created using the credential bundle returned from Turnkey after creating a read-write session.
Future<void> loginWithPasskey(BuildContext context) async {
setLoading('loginWithPasskey', true);
setError(null);
try {
final stamper =
PasskeyStamper(PasskeyStamperConfig(rpId: EnvConfig.rpId));
final httpClient = TurnkeyClient(
config: THttpConfig(baseUrl: EnvConfig.turnkeyApiUrl),
stamper: stamper);
final targetPublicKey = await sessionProvider.createEmbeddedKey();
final sessionResponse = await httpClient.createReadWriteSession(
input: CreateReadWriteSessionRequest(
type: CreateReadWriteSessionRequestType
.activityTypeCreateReadWriteSessionV2,
timestampMs: DateTime.now().millisecondsSinceEpoch.toString(),
organizationId: EnvConfig.organizationId,
parameters: CreateReadWriteSessionIntentV2(
targetPublicKey: targetPublicKey)));
final credentialBundle = sessionResponse
.activity.result.createReadWriteSessionResultV2?.credentialBundle;
if (credentialBundle != null) {
await sessionProvider.createSession(credentialBundle);
}
} catch (error) {
setError(error.toString());
} finally {
setLoading('loginWithPasskey', false);
}
}
Here's an example of auto login and logout functionality. This is done by adding a listener to the SessionProvider. Listeners will be notified when the session is created or expired.
// login_screen.dart
void autoLogin() {
if (sessionProvider.session != null &&
sessionProvider.session!.expiry >
DateTime.now().millisecondsSinceEpoch) {
Navigator.pushReplacementNamed(context, '/dashboard');
print('Logged in! Redirecting to the dashboard.');
}
}
sessionProvider.addListener(autoLogin);
// dashboard_screen.dart
void autoLogout() async {
if (sessionProvider.session == null ||
sessionProvider.session!.expiry <=
DateTime.now().millisecondsSinceEpoch) {
Navigator.pushReplacementNamed(context, '/login');
print('Session expired. Please log in again.');
}
}
sessionProvider.addListener(autoLogout);
For more code references, take a look at this file from our Flutter demo app.