JWT authentication for Flutter mobile app integrations.
flasho.auth
flasho.auth
JWT authentication is for mobile app integrations. For server-side or website integrations use an API key instead.
login()
Log in with dashboard email and password. The token is stored automatically.
final flasho = FlashoClient(token: 'placeholder');
final result = await flasho.auth.login(
email: '[email protected]',
password: 'your-password',
);
print(result.token); // eyJ...
print(result.user.email); // [email protected]
print(result.merchant.sellerName); // "My Restaurant"
print(result.merchant.billingMode); // BillingMode.prepaid
print(result.merchant.walletBalance); // "10.000"
// No setup needed — all subsequent calls use the JWT
final data = await flasho.account.bootstrap();Response fields
| Field | Type | Description |
|---|---|---|
token | String | JWT for subsequent requests |
user.id | String | Internal user ID |
user.email | String | Account email |
user.name | String | Display name |
user.role | String | Always "MERCHANT" |
merchant.id | String | Internal merchant ID |
merchant.sellerId | String | Merchant code (e.g. M001) |
merchant.sellerName | String | Store name |
merchant.billingMode | BillingMode | prepaid or postpaid |
merchant.walletBalance | String | Current balance in KWD |
merchant.scheduledDeliveryEnabled | bool | Whether scheduled delivery is on |
⚠️ Token expiry
JWTs expire. Handle FlashoApiException with isUnauthorized == true by re-calling login() and retrying the request.
Flutter login screen example
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@override
State<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _loading = false;
String? _error;
Future<void> _login() async {
setState(() { _loading = true; _error = null; });
try {
final flasho = context.read<FlashoClient>();
final result = await flasho.auth.login(
email: _emailController.text.trim(),
password: _passwordController.text,
);
// Navigate to home with merchant info
if (mounted) {
Navigator.pushReplacementNamed(context, '/home',
arguments: result.merchant);
}
} on FlashoApiException catch (e) {
setState(() => _error = e.message);
} on FlashoNetworkException catch (_) {
setState(() => _error = 'Network error. Check your connection.');
} finally {
if (mounted) setState(() => _loading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
keyboardType: TextInputType.emailAddress,
),
const SizedBox(height: 16),
TextField(
controller: _passwordController,
decoration: const InputDecoration(labelText: 'Password'),
obscureText: true,
),
const SizedBox(height: 24),
if (_error != null) ...[
Text(_error!, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 12),
],
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _loading ? null : _login,
child: _loading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Sign in'),
),
),
],
),
),
);
}
}