The Application Portal is a central hub that connects you to other company systems and services. Think of it as an app launcher for all your work tools.
It's a dashboard displaying all available applications and systems that you can access using your DTR account. No need to remember multiple passwords!
✅ Single Sign-On (SSO) - Login once, access multiple systems
✅ App Launcher - Quick access to all connected applications
✅ Seamless Integration - Your DTR credentials work everywhere
✅ Secure Authentication - Encrypted token-based access
✅ Direct Links - Browse applications without logging in
Depending on your organization, available applications might include:
📊 HR Management System
💼 Project Management Tool
📧 Email & Communication
📁 Document Management
💰 Payroll System
📈 Analytics Dashboard
🏢 Intranet Portal
👥 Employee Directory
Option 1: From Home
Login to DTR System
↓
Click "Apps" button (top navigation)
↓
Application Portal Opens
Option 2: Direct URL
Navigate to: https://dtr.company.com/apps
Option 3: Navigation Menu
Top-right Menu → Applications → Click
┌─────────────────────────────────────────────────────────┐
│ APPLICATION PORTAL │
├─────────────────────────────────────────────────────────┤
│ │
│ ⚠️ BETA NOTE: Features may change │
│ │
│ APPS GRID (6-column layout) │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ Home │ │ App1 │ │ App2 │ │ App3 │ │ App4 │ │
│ │ 🏠 │ │ 📊 │ │ 💼 │ │ 📧 │ │ 📁 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ App5 │ │ App6 │ │ App7 │ │ App8 │ │ App9 │ │
│ │ 💰 │ │ 📈 │ │ 🏢 │ │ 👥 │ │ 🎯 │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ (Scrollable to see more apps) │
│ │
└─────────────────────────────────────────────────────────┘
┌──────────────┐
│ [ICON] │ ← App icon image (if available)
│ App Name │ ← Application name
└──────────────┘
▲
Hover effect:
- Lifts up slightly
- Shadow increases
- Indicates clickable
┌──────────────┐
│ [HOME] │ ← Links to DTR Dashboard
│ Home │
└──────────────┘
Step 1: Find the App
Scroll through the grid to find the application you need.
Examples:
🏢 HR System - Employee records and benefits
💼 Project Tools - Task management and collaboration
📊 Analytics - Reports and dashboards
📧 Communication - Email and messaging
💰 Payroll - Salary and compensation info
Step 2: Click the App
Click on any app card to open its details modal.
[Click] → Modal Opens ↓
Step 3: Modal Details
┌──────────────────────────────────────┐
│ APPLICATION DETAILS │
├──────────────────────────────────────┤
│ │
│ [APP ICON] │
│ │
│ Application Name │
│ │
│ ┌─────────────────────────────────┐│
│ │ [Login (SSO)] [View Page] ││
│ └─────────────────────────────────┘│
│ │
│ [X] Close Button │
│ │
└──────────────────────────────────────┘
Each application modal has up to 2 buttons:
| Button | When Available | Action |
|---|---|---|
| Login (SSO) | If SSO enabled | Auto-login with your DTR account |
| View Page | Always | Opens app in new window |
SSO (Single Sign-On) allows you to:
You Click [Login (SSO)]
↓
System Creates Secure Token
├─ Your User ID
├─ Email
├─ Name & Roles
└─ Expiry Time (60 minutes)
↓
Token Gets Encrypted
├─ Uses app's secret key
├─ Impossible to modify
└─ Timestamped
↓
You're Redirected to App
├─ Browser opens new window
├─ Token sent in URL
└─ App verifies token
↓
App Authenticates You
├─ Validates your identity
├─ Creates session
├─ Logs you in automatically
└─ No password needed!
↓
✅ You're Logged In!
Step 1: Find App with SSO
Look for apps with blue button:
┌──────────────────────────────┐
│ [Login (SSO)] ← Blue button │
│ [View Page] ← Gray button │
└──────────────────────────────┘
Step 2: Click "Login (SSO)"
[Login (SSO)] ← Click here
↓
Processing...
Step 3: Wait for Redirect
┌──────────────────────────────┐
│ 🔄 AUTHENTICATING... │
│ │
│ Please wait while we log │
│ you into the application. │
│ │
└──────────────────────────────┘
Step 4: App Opens in New Window
✅ New Tab: [Application Name]
Your account: juan@company.com
Status: ✅ Logged In
You're now authenticated and can use the application!
Why is SSO Secure?
✅ Encrypted Token - Cannot be read or modified
✅ Time Limit - Token expires after 60 minutes
✅ Unique Secret - Each app has its own encryption key
✅ No Password Shared - Only identifier is sent
✅ Server Verification - App verifies token validity
Example Token (Encrypted):
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
[Impossible to read without the secret key]
When you use SSO, the app receives:
{
"app_id": 1,
"user_id": 5,
"email": "juan.delacruz@company.com",
"name": "Juan Dela Cruz",
"roles": ["employee", "team-lead"],
"expiry": 1733347200
}
Note: Your password is NEVER sent to other applications!
If you want to access an app without automatic login:
┌──────────────────────────────┐
│ [Login (SSO)] │
│ [View Page] ← Click here │
└──────────────────────────────┘
When to Use This:
Symptom: Only "View Page" button shows, no "Login (SSO)"
Reason: SSO is not enabled for that application
Solution:
Symptom: Error message after clicking SSO button
❌ "Failed to process SSO login: [error]"
Solutions:
Symptom: Error message saying "Token expired"
Reason: Took too long to login (>60 min token)
Solution:
Symptom: Blank page or error after SSO redirect
Solutions:
Symptom: Logged in but cannot access app
Reason: Your role doesn't have permission
Solution:
Q: Why use SSO instead of password?
A: More secure, faster login, no password sharing between apps.
Q: Is my DTR password sent to other apps?
A: No, never. Only a secure encrypted token is sent.
Q: What if I forget the app's password?
A: Use SSO instead! No app password needed.
Q: Can someone else use my SSO token?
A: No, token is encrypted and expires in 60 minutes.
Q: What if I change my DTR password?
A: SSO still works. Token is based on your ID, not password.
Q: Can I logout from all apps at once?
A: No, logout from each app individually or close all tabs.
Q: How many apps can I access?
A: As many as you have permissions for.
Q: Is SSO available on mobile?
A: Yes, same process on phone browsers.
┌─────────────────────────────────────────────────────────┐
│ DTR MAIN SYSTEM │
├─────────────────────────────────────────────────────────┤
│ │
│ User (Authenticated) │
│ ↓ │
│ AppController@apps() │
│ ├─ Fetch all apps from 'clients' table │
│ └─ Render apps/index.blade.php │
│ ↓ │
│ View: apps/index.blade.php │
│ ├─ Display app cards │
│ ├─ Alpine.js modals │
│ └─ SSO & Direct links │
│ │
│ User clicks app → Modal opens │
│ ├─ [Login (SSO)] → ApplicationLanding() │
│ └─ [View Page] → Direct redirect │
│ ↓ │
│ AppController@applicatonLanding($appId) │
│ ├─ Load app config (Client model) │
│ ├─ Generate SSO token │
│ ├─ Encrypt token with app secret │
│ └─ Redirect to external app with token │
│ ↓ │
│ EXTERNAL APP (HR System, etc) │
│ ├─ Receives encrypted token │
│ ├─ Decrypts with shared secret │
│ ├─ Validates token signature & expiry │
│ ├─ Creates user session │
│ └─ User logged in! ✅ │
│ │
└─────────────────────────────────────────────────────────┘
AppController
├── apps() method
│ ├── Fetch apps from Client model
│ └── Return to view
│
└── applicatonLanding() method
├── Get Client by ID
├── Create SSO payload
├── Encrypt with Encrypter class
├── Generate redirect URL
└── Return redirect response
File: app/Http/Controllers/AppController.php
apps()Purpose: Display all available applications
public function apps()
{
// Get all apps from Client table
$apps = Client::all();
// Return view with apps
return view('apps.index', compact('apps'));
}
Database Query:
SELECT * FROM clients;
Data Passed to View:
[
'apps' => [
Client {
id: 1,
name: "HR System",
client_id: "randomstring1",
client_secret: "randomstring2",
redirect_url: "https://hr.company.com",
is_sso: true,
icon: Attachment {}
},
Client {
id: 2,
name: "Project Tools",
...
}
]
]
applicatonLanding($appId)Purpose: Generate SSO token and redirect to external app
public function applicatonLanding($appId)
{
// 1. Load application config
$application = Client::where('id', $appId)->first();
if (!$application) {
abort(404); // App not found
}
try {
// 2. Create SSO payload (JWT-like)
$payload = json_encode([
'app_id' => $application->id,
'client_id' => $application->client_id,
'client_secret' => $application->client_secret,
'email' => auth()->user()->email,
'name' => auth()->user()->name,
'roles' => auth()->user()->roles,
'user_id' => auth()->user()->id,
'expiry' => now()->addMinutes(60)->timestamp,
]);
// 3. Encrypt payload with app's secret
$encrypter = new Encrypter(
$application->client_secret,
config('app.cipher') // 'AES-256-CBC'
);
$encoded = $encrypter->encrypt($payload);
// 4. Redirect to external app with token
return redirect()->away(
$application->redirect_url . '/sso-login?token=' . urlencode($encoded)
);
} catch (\Exception $e) {
return redirect()->back()->with(
'error',
'Failed to process SSO login: ' . $e->getMessage()
);
}
}
Step-by-Step Explanation:
Load App Configuration
$application = Client::where('id', $appId)->first();
Get app settings from database
Create Payload
$payload = json_encode([...])
JSON object containing user & app info
Encrypt
$encrypter = new Encrypter($secret, 'AES-256-CBC');
$encoded = $encrypter->encrypt($payload);
AES-256 encryption (military-grade)
Redirect
redirect()->away($url . '?token=' . $encoded);
Browser redirects to external app
{
"app_id": 1,
"client_id": "abc123def456...",
"client_secret": "xyz789uvw...",
"email": "juan.delacruz@company.com",
"name": "Juan Dela Cruz",
"roles": ["employee", "team-lead"],
"user_id": 5,
"expiry": 1733347200
}
Field Descriptions:
| Field | Purpose | Example |
|---|---|---|
| app_id | Identify which app this is for | 1 |
| client_id | App's public identifier | 32-char random string |
| client_secret | Encryption key (also app identifier) | 32-char random string |
| User's email | juan@company.com | |
| name | User's full name | Juan Dela Cruz |
| roles | User's system roles | ["employee"] |
| user_id | User's DTR ID | 5 |
| expiry | Unix timestamp (token expires) | 1733347200 |
Algorithm: AES-256-CBC
Plain Text Payload
↓
Add padding (PKCS7)
↓
Generate random IV (initialization vector)
↓
Encrypt with client_secret key
↓
Combine: IV + encrypted_data
↓
Base64 encode
↓
Encrypted Token (safe for URL)
Example:
Before: {"email":"juan@company.com", ...}
After: eyJpdiI6Ij...ZjFyTnJFZHMrb...==
Token Created: 2025-12-04 08:30:00
Expiry Time: +60 minutes
Token Expires: 2025-12-04 09:30:00
After 60 minutes:
File: app/Models/Client.php
class Client extends Model
{
use HasFactory;
protected $fillable = [
'name',
'client_id',
'client_secret',
'redirect_url',
'is_sso'
];
// Relationship to icon/image
public function icon()
{
return $this->morphOne(Attachment::class, 'attachable');
}
// Auto-generate IDs on creation
public static function boot()
{
parent::boot();
static::creating(function ($client) {
$client->client_id = Str::random(32);
$client->client_secret = Str::random(32);
});
}
}
Key Features:
CREATE TABLE clients (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
client_id VARCHAR(255) UNIQUE NOT NULL,
client_secret VARCHAR(255) NOT NULL,
redirect_url TEXT NOT NULL,
is_sso BOOLEAN DEFAULT true,
created_at TIMESTAMP,
updated_at TIMESTAMP
);
Column Descriptions:
| Column | Type | Purpose |
|---|---|---|
| id | BIGINT | Primary key |
| name | VARCHAR | App name (e.g., "HR System") |
| client_id | VARCHAR | Public ID (random 32 chars) |
| client_secret | VARCHAR | Encryption key (random 32 chars) |
| redirect_url | TEXT | External app URL |
| is_sso | BOOLEAN | Enable/disable SSO feature |
| created_at | TIMESTAMP | Record created time |
| updated_at | TIMESTAMP | Last modified time |
// Get app icon
$app = Client::with('icon')->first();
echo $app->icon->path; // /storage/app/icons/hr-system.png
Morphable Relationship:
// In Attachment model
public function attachable()
{
return $this->morphTo();
}
// In Client model
public function icon()
{
return $this->morphOne(Attachment::class, 'attachable');
}
Laravel Encrypter Class:
use Illuminate\Encryption\Encrypter;
$encrypter = new Encrypter(
$secret_key, // client_secret
'AES-256-CBC' // cipher algorithm
);
// Encrypt
$encrypted = $encrypter->encrypt($payload);
// Decrypt (done by external app)
$decrypted = $encrypter->decrypt($encrypted);
Security Levels:
✅ Level 1: HTTPS (data in transit)
✅ Level 2: AES-256 encryption (data at rest)
✅ Level 3: Signature validation (prevent tampering)
✅ Level 4: Timestamp validation (prevent replay)
What the receiving app must do:
// External app: HR System (https://hr.company.com)
// 1. Get encrypted token from URL
$token = request()->input('token');
// 2. Load DTR app config (must know client_secret)
$clientSecret = config('dtr.client_secret');
// 3. Decrypt with same secret
$encrypter = new Encrypter($clientSecret, 'AES-256-CBC');
$payload = $encrypter->decrypt($token);
$data = json_decode($payload, true);
// 4. Validate expiry time
if ($data['expiry'] < time()) {
abort(401, 'Token expired');
}
// 5. Validate client_id matches
if ($data['client_id'] !== config('dtr.client_id')) {
abort(401, 'Invalid client');
}
// 6. Create user session
auth()->login(User::findOrCreate($data['email']));
How External App Gets Secret:
Example HR System Config:
// config/dtr.php
return [
'client_id' => 'abc123def456...',
'client_secret' => 'xyz789uvw...',
'redirect_url' => 'https://hr.company.com/sso-login'
];
✅ DO:
❌ DON'T:
Step 1: Create Client in DTR Admin
# Via admin panel or artisan command
php artisan tinker
> Client::create([
'name' => 'HR System',
'redirect_url' => 'https://hr.company.com/sso-login',
'is_sso' => true
])
Step 2: Get Credentials
> $app = Client::where('name', 'HR System')->first()
> $app->client_id // Share with HR admin
> $app->client_secret // Share with HR admin (securely!)
Step 3: Configure External App
HR system admin enters in their config:
'dtr_client_id' => 'abc123...',
'dtr_client_secret' => 'xyz789...',
Step 4: Test SSO
DTR Routes:
// routes/web.php
Route::get('/apps', [AppController::class, 'apps'])
->name('apps.index');
Route::get('/apps/landing/{appId}',
[AppController::class, 'applicatonLanding'])
->name('apps.landing');
URL Examples:
Display apps:
https://dtr.company.com/apps
Initiate SSO for app #1:
https://dtr.company.com/apps/landing/1
After SSO (redirects to):
https://hr.company.com/sso-login?token=eyJ...
File: resources/views/apps/index.blade.php
Key Parts:
<!-- Fetch apps from controller -->
@foreach ($apps as $app)
<!-- App Card -->
<div x-data="{ showModal: false }">
<a @click.prevent="showModal = true">
<!-- App icon & name -->
</a>
<!-- Modal Dialog -->
<div x-show="showModal">
<!-- Show app details -->
@if ($app->is_sso)
<!-- SSO button -->
<a href="{{ route('apps.landing', ['appId' => $app->id]) }}">
Login (SSO)
</a>
@endif
<!-- Direct link -->
<a href="{{ $app->redirect_url }}" target="_blank">
View Page
</a>
</div>
</div>
@endforeach
| Component | Technology | Purpose |
|---|---|---|
| Controller | Laravel | Handle requests & SSO logic |
| Model | Eloquent | Database access |
| Encryption | AES-256-CBC | Secure token generation |
| View | Blade + Alpine.js | App launcher UI |
| Routes | Laravel Routes | URL mapping |
Documentation Version: 1.0
Last Updated: December 4, 2025
Status: ✅ Complete