Debug School

rakesh kumar
rakesh kumar

Posted on

How to Implement Secure Login with Token-Based Authentication in Laravel and Flutter

Frontend - Flutter

Step 1: Add Required Dependencies
In your pubspec.yaml, add the following dependencies:

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3
  shared_preferences: ^2.0.6
Enter fullscreen mode Exit fullscreen mode

Then run flutter pub get to install the dependencies.

Step 2: Flutter Code for Login and User Fetching
Create two files: login_screen.dart and home_screen.dart.

login_screen.dart
This screen will allow the user to log in by sending the email and password to the Laravel backend.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  Future<void> _login() async {
    final String email = _emailController.text;
    final String password = _passwordController.text;

    final response = await http.post(
      Uri.parse('http://your-laravel-api-url/api/login'), // Replace with your Laravel API URL
      headers: {'Content-Type': 'application/json'},
      body: json.encode({'email': email, 'password': password}),
    );

    if (response.statusCode == 200) {
      final token = json.decode(response.body)['token'];

      SharedPreferences prefs = await SharedPreferences.getInstance();
      await prefs.setString('token', token); // Store the token

      Navigator.pushReplacementNamed(context, '/home'); // Navigate to home screen
    } else {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Login failed')));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: _passwordController,
              obscureText: true,
              decoration: InputDecoration(labelText: 'Password'),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _login,
              child: Text('Login'),
            ),
          ],
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

home_screen.dart
This screen will fetch the authenticated user's data from the Laravel backend using the token stored in shared preferences.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  String _userData = 'Fetching...';

  Future<void> _fetchUserData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String token = prefs.getString('token') ?? '';

    final response = await http.get(
      Uri.parse('http://your-laravel-api-url/api/user'), // Replace with your Laravel API URL
      headers: {
        'Authorization': 'Bearer $token', // Send the token in the Authorization header
      },
    );

    if (response.statusCode == 200) {
      var data = json.decode(response.body);
      setState(() {
        _userData = 'User Data: \nName: ${data['name']}\nEmail: ${data['email']}';
      });
    } else {
      setState(() {
        _userData = 'Failed to fetch user data';
      });
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Text(_userData),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

main.dart
This file will initialize the app and manage routing.

import 'package:flutter/material.dart';
import 'login_screen.dart';
import 'home_screen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Token Authentication',
      initialRoute: '/',
      routes: {
        '/': (context) => LoginScreen(),
        '/home': (context) => HomeScreen(),
      },
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Backend - Laravel

Step 1: Create Laravel Project and Set Up Authentication
Create a new Laravel project:

composer create-project --prefer-dist laravel/laravel tokenAuthApp
cd tokenAuthApp
php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Create the migration to add api_token to the users table:

php artisan make:migration add_api_token_to_users_table --table=users
Enter fullscreen mode Exit fullscreen mode

In the migration file, add:

// database/migrations/xxxx_xx_xx_add_api_token_to_users_table.php
public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('api_token', 80)->unique()->nullable()->default(null);
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('api_token');
    });
}
Enter fullscreen mode Exit fullscreen mode

Run the migration:

php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the Controller
Run the following command to create the AuthController:

php artisan make:controller AuthController
Enter fullscreen mode Exit fullscreen mode

In AuthController.php, write the functions for login and fetching user data.

// app/Http/Controllers/AuthController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        // Validate the input
        $request->validate([
            'email' => 'required|email',
            'password' => 'required',
        ]);

        // Check user credentials
        $user = User::where('email', $request->email)->first();
        if ($user && Hash::check($request->password, $user->password)) {
            // Generate a new token
            $token = Str::random(60);
            $user->api_token = $token;
            $user->save();

            return response()->json(['token' => $token]);
        }

        return response()->json(['error' => 'Unauthorized'], 401);
    }

    public function getUserData(Request $request)
    {
        // Get the token from the Authorization header
        $token = $request->header('Authorization');
        if (!$token) {
            return response()->json(['error' => 'No token provided'], 401);
        }

        // Remove "Bearer " from token
        $token = str_replace('Bearer ', '', $token);

        // Validate the token and find the user
        $user = User::where('api_token', $token)->first();
        if (!$user) {
            return response()->json(['error' => 'Invalid token'], 401);
        }

        // Return user data
        return response()->json([
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
        ], 200);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Define Routes
In routes/api.php, add the following routes:

use App\Http\Controllers\AuthController;

Route::post('login', [AuthController::class, 'login']);
Route::get('user', [AuthController::class, 'getUserData']);
Enter fullscreen mode Exit fullscreen mode

Step 4: Set Up Authentication Guard
In config/auth.php, configure the api guard to use the token driver.

// config/auth.php
'guards' => [
    'api' => [
        'driver' => 'token',
        'provider' => 'users',
    ],
],
Enter fullscreen mode Exit fullscreen mode

Step 5: Testing
Now you can test the entire flow:

Start your Laravel server:

php artisan serve
Enter fullscreen mode Exit fullscreen mode

how-authentication-is-managed-by-token-and-session
how-laravel-manages-user-login-and-session-id-storage

Top comments (0)