Wednesday, June 18, 2025

Implementation of seamless authentication between two Laravel apps

 

When a user logs in to one application, they should also be authenticated in other application without logging in again.

1. Use a Common Authentication System

Ensure both Laravel apps share the same user database (either directly or via API).


2. Use tymon/jwt-auth in both apps

Install JWT package in both:

composer require tymon/jwt-auth
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider" php artisan jwt:secret

Do this in both apps. Say App A and App B


3. Generate Token in App A on Login

In App A, modify the login logic to generate a JWT token:

use Tymon\JWTAuth\Facades\JWTAuth;
public function login(Request $request) { $credentials = $request->only('email', 'password'); if (!$token = JWTAuth::attempt($credentials)) { return response()->json(['error' => 'Invalid credentials'], 401); } // Send token to front-end return response()->json(['token' => $token]); }

4. Share JWT Token with App B

When user logs in:

  1. Save token in a secure cookie:


return response()->json(['success' => true])->cookie( 'jwt_token', $token, 60, '/', '.seellab.com', true, true, false, 'Strict' );

✅ This cookie is available to all subdomains, like  App A and App B

  1. Alternatively, you can redirect to App B with token in query:

a
https://appbUrl/auth/jwt-login?token=xyz123

5. Accept and Authenticate in App B

In AppB, create a route like:

Route::get('/auth/jwt-login', function (Request $request) { $token = $request->get('token') ?? $request->cookie('jwt_token'); try { $user = JWTAuth::setToken($token)->authenticate(); Auth::login($user); return redirect('/dashboard'); // or wherever } catch (\Exception $e) { return redirect('/login')->withErrors('Token Invalid'); } });

You can auto-trigger this on page load, or have a middleware that checks and redirects accordingly.


6. Keep It Secure

  • Use HTTPS.

  • Mark cookie as Secure, HttpOnly, and SameSite=Strict if possible.

  • Tokens should expire, and refresh tokens can be used optionally.

  • If hosting under different domains (not subdomains), cookies won't be shareable — you'll need to redirect with the token.


Optional: Middleware in App B

Create a middleware to auto-login using the JWT cookie if user not logged in:

public function handle($request, Closure $next)
{ if (!Auth::check() && $request->cookie('jwt_token')) { try { $user = JWTAuth::setToken($request->cookie('jwt_token'))->authenticate(); Auth::login($user); } catch (\Exception $e) { // token expired or invalid } } return $next($request); }

Summary

FeatureImplementation
Token Generation            On login in App A
Token SharingSecure Cookie or URL param
Token ReadingApp B reads token from cookie/URL
Login SessionAuth::login($user) in App B
SecurityHTTPS, HttpOnly, SameSite, Token Expiry

Thursday, February 27, 2025

Implementation of Tabview in Laravel

To create a tabbed view in Laravel Blade for "My Organizations" and "All Organizations," you can use Bootstrap, a popular CSS framework. Below is an example:

Steps:

  1. Add Bootstrap CSS and JS:
    Include the Bootstrap CSS and JS files in your Blade layout file, e.g., app.blade.php.

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
  2. Create a Blade File with Tabs:
    Create a Blade view file, e.g., organizations.blade.php.

    <!-- resources/views/organizations.blade.php -->
    <div class="container mt-5"> <ul class="nav nav-tabs" id="organizationTabs" role="tablist"> <!-- Tab Links --> <li class="nav-item" role="presentation"> <button class="nav-link active" id="my-organizations-tab" data-bs-toggle="tab" data-bs-target="#my-organizations" type="button" role="tab" aria-controls="my-organizations" aria-selected="true"> My Organizations </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="all-organizations-tab" data-bs-toggle="tab" data-bs-target="#all-organizations" type="button" role="tab" aria-controls="all-organizations" aria-selected="false"> All Organizations </button> </li> </ul> <div class="tab-content" id="organizationTabsContent"> <!-- My Organizations Tab --> <div class="tab-pane fade show active" id="my-organizations" role="tabpanel" aria-labelledby="my-organizations-tab"> <h3 class="mt-3">My Organizations</h3> <ul> @foreach ($myOrganizations as $organization) <li>{{ $organization->name }}</li> @endforeach </ul> </div> <!-- All Organizations Tab --> <div class="tab-pane fade" id="all-organizations" role="tabpanel" aria-labelledby="all-organizations-tab"> <h3 class="mt-3">All Organizations</h3> <ul> @foreach ($allOrganizations as $organization) <li>{{ $organization->name }}</li> @endforeach </ul> </div> </div> </div>
  3. Pass Data to the View:
    In your controller, pass the myOrganizations and allOrganizations collections to the view.

    public function showOrganizations()
    { $myOrganizations = Organization::where('user_id', auth()->id())->get(); $allOrganizations = Organization::all(); return view('organizations', compact('myOrganizations', 'allOrganizations')); }
  4. Route to the View:
    Add a route for the controller method in web.php.

    Route::get('/organizations', [OrganizationController::class, 'showOrganizations'])->name('organizations.index');

Result:

  • A tabbed interface where:
    • The "My Organizations" tab lists only the organizations related to the logged-in user.
    • The "All Organizations" tab lists all organizations in the database.

Friday, January 17, 2025

Estimating the development timeline for an API when SQL queries are ready

Estimating the development timeline for an API when SQL queries are ready involves evaluating several factors. Here's a step-by-step approach:

1. Define API Scope

  • Number of Endpoints: Count how many API endpoints need to be created.
  • Complexity per Endpoint: Consider if endpoints are simple (e.g., a single query) or complex (e.g., require multiple queries or custom logic).
  • Authentication and Authorization: Determine if additional work is needed for securing the API.

2. Assess Development Components

  • Data Layer: Since SQL queries are ready, consider if additional transformations or validations are needed before returning data.
  • Business Logic: Identify if any specific computations or logic need to be applied to the data retrieved by SQL.
  • API Design:
    • Standardize response formats (e.g., JSON, XML).
    • Error handling and status codes.
  • Documentation: Include time for creating API documentation (e.g., Swagger, Postman).

3. Select Tools and Frameworks

  • Framework Choice: The time required may vary depending on the API framework or language (e.g., Flask, Django, Express.js).
  • Existing Boilerplate: If you have a starter template or boilerplate, it can save significant time.

4. Allocate Time per Endpoint

  • Simple endpoints: 1–2 hours (direct query mapping).
  • Medium complexity: 3–5 hours (data transformation or minor business logic).
  • High complexity: 6+ hours (multiple queries, external integrations).

5. Include Testing

  • Unit testing for individual functions.
  • Integration testing for endpoints.
  • Load testing if performance is critical.

6. Deployment and Setup

  • Include time for setting up the server, deploying the API, and configuring CI/CD pipelines.

7. Buffer for Debugging

  • Add a buffer of 10–20% for unforeseen issues, such as debugging or performance optimizations.

Example Timeline

TaskTime Estimate
API design (initial)4–8 hours
Simple endpoints1–2 hours/endpoint
Medium complexity endpoints3–5 hours/endpoint
High complexity endpoints6–10 hours/endpoint
Authentication setup6–10 hours
Testing10–15% of development time
Deployment and setup4–8 hours

Tips for Accuracy

  • Break down tasks as granularly as possible.
  • Review estimates with the team (if applicable).
  • Use past project timelines as references.

Wednesday, January 15, 2025

Allowed memory size of 134217728 bytes exhausted (tried to allocate 20971520 bytes) while accessing a page of the site

 Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted error in my web application, while accessing a page. To solve this issue, we have to do a configuration change in php.ini of our web server.

Follow these steps to update memory limit to resolve this error from the Mac/Ununtu terminal:

  1. Determine PHP version from terminal

RUN: php -v

  1. Navigate to php.ini file

REFERENCE: nano /etc/php/{PHP_VERSION}/php.ini

RUN: nano /etc/php/8.3/php.ini

  1. Use up and down arrows to locate memory storage and update storage allocation (this was surprisingly far down) memory_limit = 128M

Update to 256M

  1. Save and exit php.ini

Ctrl + O to save changes in nano

Enter to save to file

Ctrl + X to exit

This resolved this error for me! Hope this helps

Tuesday, January 7, 2025

How to get the auto incremented id after adding the data in mysql

 In one of the project we were working on, we had a situation, where we need to add a record to the table of the database. The added record id is auto incremented in database. This id needs to added to another table with some more data. Now the issue here is how to get the auto increamented value of the previous table. 

In PHP, you can retrieve the auto-incremented ID generated by a INSERT operation in a MySQL database using the mysqli_insert_id() function. Here's how you can do it:

Example Code

<?php // Database connection $servername = "localhost"; $username = "root"; $password = ""; $database = "your_database"; $conn = new mysqli($servername, $username, $password, $database); // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } // Insert query $sql = "INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2')"; if ($conn->query($sql) === TRUE) { // Get the last inserted ID $last_id = $conn->insert_id; echo "New record created successfully. Last inserted ID is: " . $last_id; } else { echo "Error: " . $sql . "<br>" . $conn->error; } // Close connection $conn->close(); ?>

Explanation

  1. Database Connection: Establishes a connection to the MySQL database using mysqli.
  2. Insert Query: Executes an INSERT statement.
  3. Retrieve Last ID:
    • $conn->insert_id retrieves the auto-incremented ID of the last inserted record.
  4. Error Handling: Checks if the query was successful before attempting to retrieve the ID.
  5. Close Connection: Always close the database connection after performing operations.

Notes

  • Make sure the column is defined as AUTO_INCREMENT in the table schema.
  • If you're using a database abstraction library like PDO, you can use PDO::lastInsertId() instead.
  • Ensure proper escaping or use prepared statements to prevent SQL injection. For example:

$stmt = $conn->prepare("INSERT INTO your_table (column1, column2) VALUES (?, ?)"); $stmt->bind_param("ss", $value1, $value2); $stmt->execute(); $last_id = $stmt->insert_id; $stmt->close();

This approach is more secure and should be preferred for user input.

In Laravel, retrieving the auto-incremented ID after inserting a record is straightforward, especially if you are using Eloquent or the query builder.
Using Eloquent
If you are using Eloquent, the save method or the create method automatically returns the auto-incremented ID of the record.

// Example 1: Using save()
$model = new YourModel();
$model->column1 = 'value1';
$model->column2 = 'value2';
$model->save();
$lastInsertedId = $model->id; // Retrieves the auto-incremented ID
// Example 2: Using create()
$model = YourModel::create([
'column1' => 'value1',
'column2' => 'value2',
]);
$lastInsertedId = $model->id; // Retrieves the auto-incremented ID

Using Query Builder

If you are using Laravel's query builder, you can use the insertGetId method, which inserts a record and directly returns the auto-incremented ID.

$lastInsertedId = DB::table('your_table')->insertGetId([
'column1' => 'value1',
'column2' => 'value2',
]);
echo "The last inserted ID is: " . $lastInsertedId;

Explanation
Eloquent Approach:
  • $model->save(): Saves the record to the database and updates the $model->id property with the auto-incremented ID.
  • YourModel::create(): Inserts the record and returns the model instance with the id property set.
  • Ensure that the $fillable property in your model is defined for mass assignment in create().
Query Builder Approach:
  • insertGetId: Inserts the record and directly returns the ID of the inserted record.
Notes
  • Eloquent automatically manages timestamps (created_at, updated_at) if the table has them, so you don't need to handle them manually.
  • If using create(), make sure the YourModel class has the $fillable or $guarded property defined:
  • For additional security, always validate and sanitize input data before inserting it into the database. Use Laravel's validation mechanisms.
protected $fillable = ['column1', 'column2'];