0
0
Fluttermobile~20 mins

Secure storage for credentials in Flutter - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Login Screen with Secure Storage
A login screen that saves user credentials securely on the device and retrieves them on app start.
Target UI
┌─────────────────────────────┐
│         Login Screen         │
├─────────────────────────────┤
│ Username: [______________]  │
│ Password: [______________]  │
│                             │
│ [Login]                     │
│                             │
│ Saved credentials loaded:   │
│ Username: (shown here)      │
└─────────────────────────────┘
Two TextFields for username and password input
A Login button that saves credentials securely
On app start, load saved credentials and display username below the button
Use flutter_secure_storage package for secure saving
Password field should hide input (obscure text)
UI should be simple and accessible
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: LoginScreen(),
    );
  }
}

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

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _storage = FlutterSecureStorage();
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  String _savedUsername = '';

  @override
  void initState() {
    super.initState();
    // TODO: Load saved credentials here
  }

  void _login() async {
    // TODO: Save credentials securely
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login Screen')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: _usernameController,
              decoration: const InputDecoration(labelText: 'Username'),
            ),
            TextField(
              controller: _passwordController,
              decoration: const InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _login,
              child: const Text('Login'),
            ),
            const SizedBox(height: 20),
            Text('Saved credentials loaded:'),
            Text('Username: $_savedUsername'),
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: LoginScreen(),
    );
  }
}

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

  @override
  State<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final _storage = const FlutterSecureStorage();
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  String _savedUsername = '';

  @override
  void initState() {
    super.initState();
    _loadCredentials();
  }

  Future<void> _loadCredentials() async {
    final username = await _storage.read(key: 'username') ?? '';
    final password = await _storage.read(key: 'password') ?? '';
    setState(() {
      _savedUsername = username;
      _usernameController.text = username;
      _passwordController.text = password;
    });
  }

  Future<void> _login() async {
    final username = _usernameController.text;
    final password = _passwordController.text;
    await _storage.write(key: 'username', value: username);
    await _storage.write(key: 'password', value: password);
    setState(() {
      _savedUsername = username;
    });
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Credentials saved securely')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login Screen')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: _usernameController,
              decoration: const InputDecoration(labelText: 'Username'),
            ),
            TextField(
              controller: _passwordController,
              decoration: const InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: _login,
              child: const Text('Login'),
            ),
            const SizedBox(height: 20),
            Text('Saved credentials loaded:'),
            Text('Username: $_savedUsername'),
          ],
        ),
      ),
    );
  }
}

We use the flutter_secure_storage package to save the username and password securely on the device. In initState, we load saved credentials asynchronously and update the UI. The password field uses obscureText: true to hide input. When the user taps the Login button, the credentials are saved securely and the username is displayed below. A SnackBar confirms the save action. This approach keeps sensitive data safe and improves user experience by remembering credentials.

Final Result
Completed Screen
┌─────────────────────────────┐
│         Login Screen         │
├─────────────────────────────┤
│ Username: [user123     ]    │
│ Password: [••••••••••••]    │
│                             │
│ [Login]                     │
│                             │
│ Saved credentials loaded:   │
│ Username: user123           │
└─────────────────────────────┘
User enters username and password in text fields
User taps Login button
Credentials are saved securely
Username appears below as confirmation
On app restart, saved username and password load automatically
Stretch Goal
Add a 'Logout' button that clears saved credentials from secure storage and clears the UI fields
💡 Hint
Use flutter_secure_storage's delete method for keys and set state to clear username and password controllers