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);
$user->tokens()->updateOrCreate(['application_id' => $client->id], [
'token' => $accessToken
$user->tokens()->create([
'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([
@ -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 $icon = null;
public function mount()
{
$this->loadApp(4);
}
public function updated($prop)
{
if ($prop == "query") {

View File

@ -18,7 +18,7 @@ class UserProfile extends Component
public string $name = '';
public string $email = '';
public ?string $preferred_username = null;
public string $avatar = '';
public ?string $avatar = null;
#[Validate('image|max:10000')]
public $avatarUpload;
// Password
@ -68,22 +68,26 @@ class UserProfile extends Component
$this->dispatch('profile-updated', name: $user->name);
}
/**
* Send an email verification notification to the current user.
*/
public function resendVerificationNotification(): void
public function updatePassword(): 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()) {
$this->redirectIntended(default: route('dashboard', absolute: false));
return;
throw $e;
}
$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()

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,
"requires": true,
"packages": {

View File

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

View File

@ -15,8 +15,12 @@
</div>
<div class="flex-1 flex flex-col justify-between">
<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>
@else
<flux:text>No preferred username</flux:text>
@endif
<flux:text>{{auth()->user()->email}}</flux:text>
</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::get('userinfo', [OIDCController::class, 'userinfo'])->name('auth.userinfo');
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/openid-configuration', [OIDCController::class, 'openidConfig'])->name('auth.openid-configuration');