Top Ad unit 728 × 90

Welcome !!! To The World of Programming

OOPS FEATURES

Oops

Flutter Mobile App with Flask REST API Authentication

 Flutter App Connecting to Flask API 

  (Secure Login, and Role-Based Access Control)

We have implemented a simple RESTful API using Flask for user registration, login, and role-based access control. The system defines four endpoints: register, login, dashboard, and admin_panel, demonstrating secure access with JWT  authentication and role verification.

Flutter Mobile App + Flask REST API | Login Authentication with JWT | Full Practical Demo:

Today's, we are building a simple Flutter mobile app that connects to our Flask REST API for user authentication.

We’ll cover login, token-based access, and protected dashboard access — all using Flutter and Flask.

We built two simple screens:"

       Login Screen — takes username and password and calls /login API.

       Dashboard Screen — calls /dashboard API with JWT Token after successful login.

Flutter:

Flutter is an open-source UI software development toolkit created by Google for building cross-platform applications from a single codebase.

What Flutter Does?

 Builds native-compiled apps for:

     📱 Mobile: iOS & Android

     🖥️ Desktop: Windows, macOS, Linux

     🌐 Web: Browser-based apps

 Uses Dart (a modern, fast programming language also by Google).

Why Choose Flutter?

🚀   Fast Development: Hot reload saves hours.

🎨 Beautiful UIs: Customizable widgets.

📦 One Codebase: Maintain iOS/Android/web simultaneously.

 💡 Backed by Google: Strong community & updates.

What is an AVD?

AVD (Android Virtual Device) is an emulator that lets you test Android apps on your computer without needing a physical device.

  •  A software replica of a physical Android device (phone, tablet, etc.).
  • Runs on your PC/Mac to simulate different Android versions, screen sizes, and hardware configurations.
  • Part of Android Studio (the official IDE for Android development).

Key Uses:

📱   Test apps before deploying to real devices.

🔍 Debug UI, performance, and compatibility.

🌍 Simulate different Android versions (e.g., Android 12, 13) and hardware (RAM, sensors).

How to Create an AVD?

   1.      Open Android Studio → Go to AVD Manager:

   2.      Click Create Virtual Device.

   3.      Select a device model (e.g., Pixel 6).

   4.      Choose a system image (Android version, e.g., Android 35).

   5.      Configure RAM, storage, and other settings.

   6.      Click Finish

Enable Virtualization in BIOS
(
Most important for emulators!)

Restart your PC → Enter BIOS (usually F2, Delete, or F10 at boot).

Find "Intel Virtualization Technology" (VT-x) and enable it.

Save and exit BIOS.

1. Install Android Studio

Download and install Android Studio:
👉 https://developer.android.com/studio

This will install:

  • Android Emulator
  • Android SDK
  •  AVD Manager (for managing virtual devices)

2. Install Flutter SDK (Recommended for Mobile App)

We'll use Flutter (Google's framework) — works for both Android and iOS.

Install Flutter:
👉 https://docs.flutter.dev/get-started/install

After installing Flutter:

Run in terminal: flutter doctor

Fix any missing requirements (it will guide you).

3. Set Flutter SDK Path in Android Studio

Open Android Studio → Settings → Languages & Frameworks → Flutter.

Set the Flutter SDK path (where Flutter was installed).

Example: C:\flutter or wherever you installed it.

Click Apply and OK.

4. Install Flutter and Dart Plugins

Open Android Studio → Settings → Plugins.

Search for Flutter and Dart plugins and install them.

Restart Android Studio.

1. Project Structure

/mobileapp_flask_api

  ├── lib/

      ├── main.dart

      ├── screens/

           ├── login_screen.dart

           └── dashboard_screen.dart

      ├── services/

           └── api_service.dart

  └── pubspec.yaml

The required code is as follows:


 //main.dart

import 'package:flutter/material.dart';
import 'screens/login_screen.dart';
//import 'screens/register_screen.dart';
import 'screens/dashboard_screen.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter API Client',
      debugShowCheckedModeBanner: false,
      initialRoute: '/',
      routes: {
        '/': (context) => const LoginScreen(),
       // '/register': (context) => const RegisterScreen(),
        '/dashboard': (context) => const DashboardScreen(), // << No arguments!
      },
    );
  }
}
 
  


//api_service.dart

import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class ApiService {
  static const String baseUrl = "http://10.0.2.2:5000"; // <-- Replace with your Flask API

  static final storage = FlutterSecureStorage();

  static Future<String?> login(String username, String password) async {
    final response = await http.post(
      Uri.parse('$baseUrl/login'),
      headers: {"Content-Type": "application/json"},
      body: jsonEncode({"username": username, "password": password}),
    );

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      await storage.write(key: "token", value: data["access_token"]);
      return null; // Success
    } else {
      final data = jsonDecode(response.body);
      return data["error"] ?? "Login failed";
    }
  }

  static Future<String?> register(String username, String password, String role) async {
    final response = await http.post(
      Uri.parse('$baseUrl/register'),
      headers: {"Content-Type": "application/json"},
      body: jsonEncode({"username": username, "password": password, "role": role}),
    );

    if (response.statusCode == 200) {
      return null; // Success
    } else {
      final data = jsonDecode(response.body);
      return data["error"] ?? "Registration failed";
    }
  }

  static Future<String?> dashboard() async {
    String? token = await storage.read(key: "token");
    if (token == null) return "Unauthorized";

    final response = await http.get(
      Uri.parse('$baseUrl/dashboard'),
      headers: {"Authorization": "Bearer $token"},
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body)["message"];
    } else {
      return "Access denied.";
    }
  }

  static Future<String?> adminPanel() async {
    String? token = await storage.read(key: "token");
    if (token == null) return "Unauthorized";

    final response = await http.get(
      Uri.parse('$baseUrl/admin'),
      headers: {"Authorization": "Bearer $token"},
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body)["message"];
    } else {
      return "Access denied.";
    }
  }

  static Future<void> logout() async {
    await storage.delete(key: "token");
  }
}


//login_screen.dart

import 'package:flutter/material.dart';
import '../services/api_service.dart'; // Adjust the path

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

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

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController usernameController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  bool isLoading = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Login')),
      body: Padding(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            TextField(
              controller: usernameController,
              decoration: const InputDecoration(labelText: 'Username'),
            ),
            TextField(
              controller: passwordController,
              obscureText: true,
              decoration: const InputDecoration(labelText: 'Password'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: isLoading ? null : _login,
              child: isLoading ? const CircularProgressIndicator() : const Text('Login'),
            ),
          ],
        ),
      ),
    );
  }

  Future<void> _login() async {
    setState(() {
      isLoading = true;
    });

    String username = usernameController.text.trim();
    String password = passwordController.text.trim();

    String? error = await ApiService.login(username, password);

    if (!mounted) return; // <-- ⭐ very important now!

    setState(() {
      isLoading = false;
    });

    if (error == null) {
      Navigator.pushReplacementNamed(context, '/dashboard');
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(error)),
      );
    }
  }
}


//dashboard_screen.dart

import 'package:flutter/material.dart';
import '../services/api_service.dart'; // Import your ApiService

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

  @override
  State<DashboardScreen> createState() => _DashboardScreenState();
}

class _DashboardScreenState extends State<DashboardScreen> {
  String message = "Loading...";

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

  void fetchDashboardMessage() async {
    String? response = await ApiService.dashboard(); // API call
    setState(() {
      message = response ?? "Failed to load dashboard.";
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dashboard'),
        actions: [
          IconButton(
            icon: const Icon(Icons.logout),
            onPressed: () {
              ApiService.logout(); // Clear token
              Navigator.pushNamedAndRemoveUntil(context, '/', (route) => false);
            },
          )
        ],
      ),
      body: Center(
        child: Text(
          message,
          textAlign: TextAlign.center,
          style: const TextStyle(fontSize: 24),
        ),
      ),
    );
  }
}


name: mobileapp_flask_api
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
//pubspec.yaml
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1

environment:
  sdk: ^3.7.2

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
  flutter:
    sdk: flutter
  http: ^1.2.0
  flutter_secure_storage: ^9.0.0  # For storing JWT token securely
 
 # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.8

dev_dependencies:
  flutter_test:
    sdk: flutter

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^5.0.0

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  # assets:
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/to/resolution-aware-images

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/to/asset-from-package

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/to/font-from-package




That's it for today’s tutorial! 🚀 If you enjoyed this project, don't forget to like, comment, and subscribe for more full-stack mobile + backend tutorials! In the next part, we'll go even deeper — maybe adding registration from mobile app, or admin roles!

RESTful API Services:

RESTAPI can be consumed by both Web Clients (browsers, JavaScript apps) and mobile clients (Android/iOS apps).

Why This Matters?

A well-designed REST API lets you share business logic across Web App and Mobile Apps, reducing development time and ensuring consistency.


Flutter Mobile App with Flask REST API Authentication Reviewed by Syed Hafiz Choudhary on May 12, 2025 Rating: 5

No comments:

Contact Form

Name

Email *

Message *

Powered by Blogger.
!-- JavaScript for Ad Block Detection -->