WIP
All checks were successful
linter / quality (push) Successful in 6m47s
tests / ci (push) Successful in 11m57s

This commit is contained in:
Javier Feliz 2025-07-27 23:15:54 -04:00
parent 38c0c70ded
commit 392d14e0e1
9 changed files with 77 additions and 22 deletions

View File

@ -134,8 +134,13 @@ class OIDCController extends Controller
$accessToken = Str::random(64); $accessToken = Str::random(64);
$user->tokens()->updateOrCreate(['application_id' => $client->id], [ $user->tokens()->create([
'token' => $accessToken 'application_id' => $client->id,
'token' => $accessToken,
'issued_at' => now()->toDateTimeString(),
'expires_at' => now()->addMonth()->toDateTimeString(),
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
]); ]);
return response()->json([ return response()->json([
@ -217,4 +222,9 @@ class OIDCController extends Controller
] ]
]); ]);
} }
public function logout(Request $request)
{
return view('logged-out');
}
} }

View File

@ -15,11 +15,6 @@ class AppInfoModal extends Component
public string $query = ''; public string $query = '';
public ?string $icon = null; public ?string $icon = null;
public function mount()
{
$this->loadApp(4);
}
public function updated($prop) public function updated($prop)
{ {
if ($prop == "query") { if ($prop == "query") {

View File

@ -18,7 +18,7 @@ class UserProfile extends Component
public string $name = ''; public string $name = '';
public string $email = ''; public string $email = '';
public ?string $preferred_username = null; public ?string $preferred_username = null;
public string $avatar = ''; public ?string $avatar = null;
#[Validate('image|max:10000')] #[Validate('image|max:10000')]
public $avatarUpload; public $avatarUpload;
// Password // Password
@ -68,22 +68,26 @@ class UserProfile extends Component
$this->dispatch('profile-updated', name: $user->name); $this->dispatch('profile-updated', name: $user->name);
} }
/** public function updatePassword(): void
* Send an email verification notification to the current user.
*/
public function resendVerificationNotification(): void
{ {
$user = Auth::user(); try {
$validated = $this->validate([
'current_password' => ['required', 'string', 'current_password'],
'password' => ['required', 'string', PasswordRule::defaults(), 'confirmed'],
]);
} catch (ValidationException $e) {
$this->reset('current_password', 'password', 'password_confirmation');
if ($user->hasVerifiedEmail()) { throw $e;
$this->redirectIntended(default: route('dashboard', absolute: false));
return;
} }
$user->sendEmailVerificationNotification(); Auth::user()->update([
'password' => Hash::make($validated['password']),
]);
Session::flash('status', 'verification-link-sent'); $this->reset('current_password', 'password', 'password_confirmation');
$this->dispatch('password-updated');
} }
public function render() public function render()

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('authentication_tokens', function (Blueprint $table) {
$table->string('user_agent')->nullable();
$table->string('ip')->nullable();
$table->timestamp('issued_at');
$table->timestamp('expires_at');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('authentication_tokens', function (Blueprint $table) {
//
});
}
};

2
package-lock.json generated
View File

@ -1,5 +1,5 @@
{ {
"name": "homelab-sso", "name": "authentikate",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {

View File

@ -1,8 +1,10 @@
<x-layouts.app :title="__('Dashboard')"> <x-layouts.app :title="__('Dashboard')">
<div class="max-w-4xl mx-auto py-12"> <div class="max-w-4xl mx-auto py-12">
<livewire:app-container /> <div class="grid grid-cols-2">
<div class="mt-4">
<livewire:forms.user-profile /> <livewire:forms.user-profile />
</div> </div>
<div class="mt-4">
<livewire:app-container />
</div>
</div> </div>
</x-layouts.app> </x-layouts.app>

View File

@ -15,8 +15,12 @@
</div> </div>
<div class="flex-1 flex flex-col justify-between"> <div class="flex-1 flex flex-col justify-between">
<flux:text>{{auth()->user()->name}}</flux:text> <flux:text>{{auth()->user()->name}}</flux:text>
@if (!empty(auth()->user()->preferred_username))
<flux:text>{{auth()->user()->preferred_username}} <span class="italic">(preferred username)</span> <flux:text>{{auth()->user()->preferred_username}} <span class="italic">(preferred username)</span>
</flux:text> </flux:text>
@else
<flux:text>No preferred username</flux:text>
@endif
<flux:text>{{auth()->user()->email}}</flux:text> <flux:text>{{auth()->user()->email}}</flux:text>
</div> </div>
</div> </div>

View File

@ -0,0 +1,8 @@
<x-layouts.base>
<div class="flex flex-col items-center justify-center max-w-xl mx-auto h-screen">
<flux:heading size="xl" class="mb-8">You've been logged out of this app</flux:heading>
@auth
<flux:button href="{{route('dashboard')}}">Back to dashboard</flux:button>
@endauth
</div>
</x-layouts.base>

View File

@ -38,6 +38,7 @@ Route::prefix('application/o')->group(function () {
Route::post('token', [OIDCController::class, 'token'])->withoutMiddleware(VerifyCsrfToken::class)->name('auth.token'); Route::post('token', [OIDCController::class, 'token'])->withoutMiddleware(VerifyCsrfToken::class)->name('auth.token');
Route::get('userinfo', [OIDCController::class, 'userinfo'])->name('auth.userinfo'); Route::get('userinfo', [OIDCController::class, 'userinfo'])->name('auth.userinfo');
Route::get('confirm', ConsentScreen::class)->name('auth.confirm'); Route::get('confirm', ConsentScreen::class)->name('auth.confirm');
Route::get('logout', [OIDCController::class, 'logout'])->name('auth.logout');
}); });
Route::get('.well-known/jwks.json', [OIDCController::class, 'jwks'])->name('auth.keys'); Route::get('.well-known/jwks.json', [OIDCController::class, 'jwks'])->name('auth.keys');
Route::get('.well-known/openid-configuration', [OIDCController::class, 'openidConfig'])->name('auth.openid-configuration'); Route::get('.well-known/openid-configuration', [OIDCController::class, 'openidConfig'])->name('auth.openid-configuration');