Of course. This is a practical and powerful setup. Here is a detailed, step-by-step guide to implement a simplified version of this architecture on your local machine using Laravel and XAMPP.
We will create two separate Laravel applications:
AuthServer
: This will be our centralized authentication server (auth.myhospitalnow.local
). It will run Laravel Passport.
PatientPortal
: This will be our client application (www.myhospitalnow.local
) that allows users to log in via the AuthServer
.
Prerequisites:
- XAMPP installed (which includes Apache and MySQL/MariaDB).
- Composer installed globally.
- A code editor (like Visual Studio Code).
Step 1: Configure Your Local Environment (XAMPP & Hosts)
This is the most critical step. We need to make your computer recognize auth.myhospitalnow.local
and www.myhospitalnow.local
as distinct websites.
1. Edit Your hosts
File:
This file maps domain names to IP addresses.
- Windows:
C:\Windows\System32\drivers\etc\hosts
(Open Notepad as Administrator to edit).
- macOS/Linux:
/etc/hosts
(Use sudo nano /etc/hosts
in the terminal).
Add the following lines to the end of the file:
127.0.0.1 auth.myhospitalnow.local
127.0.0.1 www.myhospitalnow.local
2. Configure Apache Virtual Hosts:
- Open your XAMPP control panel and stop Apache.
- Navigate to your XAMPP installation folder, then
apache\conf\extra\
.
- Open the file
httpd-vhosts.conf
in your code editor.
- Add the following configuration to the end of the file. Make sure to replace
C:/xampp/htdocs/
with the actual path to your XAMPP htdocs
folder.
<!-- end list -->
# Virtual Host for the Authentication Server
<VirtualHost *:80>
DocumentRoot "C:/xampp/htdocs/AuthServer/public"
ServerName auth.myhospitalnow.local
<Directory "C:/xampp/htdocs/AuthServer/public">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
# Virtual Host for the Patient Portal Client
<VirtualHost *:80>
DocumentRoot "C:/xampp/htdocs/PatientPortal/public"
ServerName www.myhospitalnow.local
<Directory "C:/xampp/htdocs/PatientPortal/public">
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
- Now, open
apache\conf\httpd.conf
and find the line #Include conf/extra/httpd-vhosts.conf
. Remove the #
at the beginning to enable it.
- Start Apache from the XAMPP control panel.
Step 2: Build the Authentication Server (AuthServer
)
1. Create the Laravel Project:
Open your terminal/command prompt, navigate to your htdocs
folder, and run:
cd C:\xampp\htdocs
composer create-project laravel/laravel AuthServer
2. Configure the Database:
- Open phpMyAdmin (
http://localhost/phpmyadmin
).
- Create a new database named
auth_server_db
.
- Open the
.env
file in the AuthServer
project and update the database connection details:
<!-- end list -->
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=auth_server_db
DB_USERNAME=root
DB_PASSWORD=
3. Install and Configure Laravel Passport (Our OAuth2 Server):
- In your terminal,
cd
into the AuthServer
project.
<!-- end list -->
cd C:\xampp\htdocs\AuthServer
# Install Passport
composer require laravel/passport
# Run migrations to create user tables etc.
php artisan migrate
# Run Passport's installation command
php artisan passport:install
The passport:install
command creates encryption keys and two special "clients" for issuing tokens.
4. Finalize Passport Setup:
app/Models/User.php
: Add the HasApiTokens
trait.
<!-- end list -->
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens; // <-- Import this
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable; // <-- Add HasApiTokens here
// ... rest of the file
}
app/Providers/AuthServiceProvider.php
: Register Passport's routes in the boot()
method.
<!-- end list -->
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport; // <-- Import this
class AuthServiceProvider extends ServiceProvider
{
// ...
public function boot(): void
{
$this->registerPolicies();
Passport::routes(); // <-- Add this line
}
}
config/auth.php
: Change the api
guard driver to passport
.
<!-- end list -->
'guards' => [
// ...
'api' => [
'driver' => 'passport', // <-- Change 'token' to 'passport'
'provider's' => 'users',
],
],
Our Auth Server is now ready!
Step 3: Build the Client Application (PatientPortal
)
1. Create the Laravel Project:
In your terminal, from the htdocs
folder, run:
cd C:\xampp\htdocs
composer create-project laravel/laravel PatientPortal
2. Configure Its Database (Optional but good practice):
Create another database in phpMyAdmin called patient_portal_db
and update the .env
file in the PatientPortal
project.
3. Install Guzzle:
This HTTP client will be used to talk to the Auth Server from our backend.
cd C:\xampp\htdocs\PatientPortal
composer require guzzlehttp/guzzle
Step 4: Connect the Two Applications
1. Create an OAuth Client on the AuthServer
:
- In your terminal,
cd
into the AuthServer
project.
- Run the following command to create a client for our
PatientPortal
:
<!-- end list -->
php artisan passport:client --authorization_code
- The command will ask you for:
- User ID: You can leave this blank for now. Press Enter.
- Client name: Enter
Patient Portal
- Redirect URI: Enter
http://www.myhospitalnow.local/auth/callback
- It will output a Client ID and Client Secret. Copy these immediately!
2. Store Credentials in the PatientPortal
:
- Open the
.env
file in the PatientPortal
project.
- Add the following lines, pasting the values you just copied.
<!-- end list -->
# ... other variables
# Auth Server Details
AUTH_SERVER_URL=http://auth.myhospitalnow.local
AUTH_SERVER_CLIENT_ID=your_client_id_here
AUTH_SERVER_CLIENT_SECRET=your_client_secret_here
AUTH_SERVER_REDIRECT_URI=http://www.myhospitalnow.local/auth/callback
Step 5: Implement the Login Flow in PatientPortal
1. Create Routes (routes/web.php
in PatientPortal
):
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
// Welcome page
Route::get('/', function () {
return view('welcome');
})->name('home');
// Routes for our OAuth flow
Route::get('/login', [AuthController::class, 'login'])->name('login');
Route::get('/auth/callback', [AuthController::class, 'callback']);
Route::get('/logout', [AuthController::class, 'logout'])->name('logout');
// A protected route to test our API call
Route::get('/my-profile', [AuthController::class, 'getProfile'])->name('profile');
2. Create the Controller (AuthController
):
Run php artisan make:controller AuthController
in the PatientPortal
terminal.
Open app/Http/Controllers/AuthController.php
and paste this code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
class AuthController extends Controller
{
public function login(Request $request)
{
$request->session()->put('state', $state = Str::random(40));
$query = http_build_query([
'client_id' => env('AUTH_SERVER_CLIENT_ID'),
'redirect_uri' => env('AUTH_SERVER_REDIRECT_URI'),
'response_type' => 'code',
'scope' => '', // You can define scopes here like 'read-profile'
'state' => $state,
]);
return redirect(env('AUTH_SERVER_URL') . '/oauth/authorize?' . $query);
}
public function callback(Request $request)
{
$state = $request->session()->pull('state');
throw_unless(strlen($state) > 0 && $state === $request->state, \InvalidArgumentException::class);
$response = Http::asForm()->post(env('AUTH_SERVER_URL') . '/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => env('AUTH_SERVER_CLIENT_ID'),
'client_secret' => env('AUTH_SERVER_CLIENT_SECRET'),
'redirect_uri' => env('AUTH_SERVER_REDIRECT_URI'),
'code' => $request->code,
]);
// Store tokens and user info in the session
$request->session()->put($response->json());
return redirect()->route('home');
}
public function getProfile(Request $request)
{
$accessToken = $request->session()->get('access_token');
// Call the Auth Server's API
$response = Http::withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $accessToken,
])->get(env('AUTH_SERVER_URL') . '/api/user');
// For demonstration, we just dump the response
return $response->json();
}
public function logout(Request $request) {
$request->session()->flush();
return redirect()->route('home');
}
}
3. Update the View (resources/views/welcome.blade.php
):
Replace the content of this file with:
<!DOCTYPE html>
<html>
<head>
<title>Patient Portal</title>
</head>
<body>
<h1>Welcome to the Patient Portal</h1>
@if(session()->has('access_token'))
<p>You are logged in!</p>
<p><a href="{{ route('profile') }}">View My Profile (from Auth Server)</a></p>
<p><a href="{{ route('logout') }}">Logout</a></p>
@else
<p><a href="{{ route('login') }}">Login with HospitalNow Auth</a></p>
@endif
</body>
</html>
Step 6: Create a User and Test Everything
1. Create a Test User on the AuthServer
:
- In your terminal,
cd
into the AuthServer
project.
- Run
php artisan tinker
.
- Inside tinker, create a user:
<!-- end list -->
\App\Models\User::create([
'name' => 'John Patient',
'email' => 'john@patient.com',
'password' => bcrypt('password')
]);
- Type
exit
to leave tinker.
2. The Final Test:
- Open your browser and go to
http://www.myhospitalnow.local
. You should see the "Login" link.
- Click the "Login" link.
- You will be redirected to
http://auth.myhospitalnow.local
. You'll see a Laravel login form.
- Log in with the credentials:
john@patient.com
and password
.
- You will be presented with an "Authorization" screen asking if you want to allow "Patient Portal" to access your account. Click Authorize.
- You will be redirected back to
http://www.myhospitalnow.local
. It should now say "You are logged in!".
- Click the "View My Profile" link. You should see the JSON data for John Patient, which was securely fetched from the
AuthServer
's API using your access token!
You have successfully implemented a centralized authentication system on your local machine! You can now expand on this by creating Doctor
and Hospital
portals, adding more roles/permissions, and building out the resource microservices.