secure_session_manager 1.0.0 copy "secure_session_manager: ^1.0.0" to clipboard
secure_session_manager: ^1.0.0 copied to clipboard

A lightweight, secure, and highly scalable session management package for Flutter with zero performance overhead when optional features are disabled.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:secure_session_manager/secure_session_manager.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize SessionManager with demo settings
  await SessionManager.instance.initialize(
    tokenProvider: MockTokenProvider(),
    idleTimeout: const Duration(seconds: 10), // Short 10s idle for demo
    enableLifecycleObserver: true,           // Validate on app resume
  );

  runApp(const MyApp());
}

/// A real-world mock token provider that simulates an API call.
class MockTokenProvider implements TokenProvider {
  @override
  Future<SessionToken> refreshToken(SessionToken currentToken) async {
    // Simulate API network delay
    await Future<void>.delayed(const Duration(seconds: 2));

    return SessionToken(
      accessToken: 'refreshed_at_${DateTime.now().second}s',
      refreshToken: 'new_refresh_${idGenerator()}',
      expiresAt: DateTime.now().add(const Duration(seconds: 30)), // Expire in 30s
    );
  }

  String idGenerator() => DateTime.now().millisecondsSinceEpoch.toString().substring(8);
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // TIP: Wrap your app in a Listener to globally detect user interaction
    // for idle detection.
    return Listener(
      onPointerDown: (_) => SessionManager.instance.touch(),
      behavior: HitTestBehavior.translucent,
      child: MaterialApp(
        title: 'Secure Session Manager Demo',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(
            seedColor: Colors.indigo,
            brightness: Brightness.light,
          ),
          useMaterial3: true,
        ),
        home: const HomeScreen(),
      ),
    );
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  String _status = 'Signed Out';
  String _token = 'No Active Session';
  bool _isRefreshing = false;
  final List<String> _logs = [];

  StreamSubscription? _eventSub;

  @override
  void initState() {
    super.initState();
    _checkInitialState();
    _listenToEvents();
  }

  Future<void> _checkInitialState() async {
    final status = await SessionManager.instance.isLoggedIn;
    if (status) {
      final session = await SessionManager.instance.getSession();
      setState(() {
        _status = 'Signed In';
        _token = session?.accessToken ?? 'Incomplete session';
      });
    }
  }

  void _listenToEvents() {
    _eventSub = SessionManager.instance.onEvent.listen((event) {
      setState(() {
        if (event is LogoutEvent) {
          _status = 'Signed Out';
          _token = 'Session Cleared';
          _log('Event: Global Logout');
        } else if (event is SessionExpiredEvent) {
          _status = 'Expired (Idle)';
          _log('Event: Idle Timeout Detected');
        } else if (event is TokenRefreshedEvent) {
          _token = event.newToken.accessToken;
          _log('Event: Token Refreshed Automatically');
        }
      });
    });
  }

  void _log(String message) {
    _logs.insert(0, "[${DateTime.now().second}s] $message");
    if (_logs.length > 5) _logs.removeLast();
  }

  Future<void> _simulateLogin() async {
    // 15 second expiry for testing auto-refresh
    final token = SessionToken(
      accessToken: 'auth_jwt_${DateTime.now().second}',
      refreshToken: 'refresh_token_xyz',
      expiresAt: DateTime.now().add(const Duration(seconds: 15)),
    );
    
    await SessionManager.instance.setSession(token);
    setState(() {
      _status = 'Signed In';
      _token = token.accessToken;
    });
    _log('Logged in (Expires in 15s)');
  }

  Future<void> _manualRefresh() async {
    setState(() => _isRefreshing = true);
    try {
      final newToken = await SessionManager.instance.refreshToken();
      setState(() => _token = newToken.accessToken);
    } catch (e) {
      _log('Refresh Error: $e');
    } finally {
      setState(() => _isRefreshing = false);
    }
  }

  Future<void> _getAccessToken() async {
    // This will trigger auto-refresh if the 15s elapsed
    final token = await SessionManager.instance.getAccessToken();
    setState(() {
      _token = token ?? 'Failed to retrieve';
    });
    _log('Requested Access Token');
  }

  @override
  void dispose() {
    _eventSub?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Session Manager'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        actions: [
          if (SessionManager.instance.isInitialized)
            IconButton(
              onPressed: () => SessionManager.instance.logout(),
              icon: const Icon(Icons.logout),
              tooltip: 'Force Logout',
            )
        ],
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24.0),
        child: Column(
          children: [
            _buildInfoCard(),
            const SizedBox(height: 24),
            Wrap(
              spacing: 12,
              runSpacing: 12,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton.icon(
                  onPressed: _simulateLogin,
                  icon: const Icon(Icons.login),
                  label: const Text('Simulate Login'),
                ),
                ElevatedButton.icon(
                  onPressed: _getAccessToken,
                  icon: const Icon(Icons.vpn_key),
                  label: const Text('Use Token (Auto-Refresh)'),
                ),
                OutlinedButton.icon(
                  onPressed: _isRefreshing ? null : _manualRefresh,
                  icon: _isRefreshing 
                    ? const SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2))
                    : const Icon(Icons.refresh),
                  label: const Text('Force Refresh'),
                ),
              ],
            ),
            const SizedBox(height: 32),
            _buildLogSection(),
            const SizedBox(height: 16),
            const Text(
              'TIP: Stop interacting for 10 seconds to trigger idle timeout.',
              style: TextStyle(fontSize: 12, fontStyle: FontStyle.italic, color: Colors.grey),
              textAlign: TextAlign.center,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildInfoCard() {
    return Card(
      elevation: 0,
      color: Theme.of(context).colorScheme.surface.withAlpha(20),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                const Text('Account Status:', style: TextStyle(fontWeight: FontWeight.bold)),
                Chip(
                  label: Text(_status),
                  backgroundColor: _status == 'Signed In' ? Colors.green.shade100 : Colors.red.shade100,
                ),
              ],
            ),
            const Divider(height: 32),
            const Align(
              alignment: Alignment.centerLeft,
              child: Text('Access Token:', style: TextStyle(fontWeight: FontWeight.bold)),
            ),
            const SizedBox(height: 8),
            Container(
              padding: const EdgeInsets.all(12),
              width: double.infinity,
              decoration: BoxDecoration(
                color: Colors.black12,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                _token,
                style: const TextStyle(fontFamily: 'monospace', fontSize: 13),
                textAlign: TextAlign.center,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildLogSection() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        const Text('Recent Activity Log:', style: TextStyle(fontWeight: FontWeight.bold)),
        const SizedBox(height: 12),
        if (_logs.isEmpty)
          const Text('No activity yet...', style: TextStyle(color: Colors.grey)),
        ..._logs.map((log) => Padding(
          padding: const EdgeInsets.only(bottom: 8.0),
          child: Row(
            children: [
              const Icon(Icons.chevron_right, size: 16, color: Colors.indigo),
              const SizedBox(width: 8),
              Text(log, style: const TextStyle(fontSize: 13)),
            ],
          ),
        )),
      ],
    );
  }
}
2
likes
0
points
142
downloads

Publisher

verified publishergreelogix.com

Weekly Downloads

A lightweight, secure, and highly scalable session management package for Flutter with zero performance overhead when optional features are disabled.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

clock, flutter, flutter_secure_storage, meta, synchronized

More

Packages that depend on secure_session_manager