Feat: Add OIDC config resolver and enhanced logging for app creation

- Introduced `OidcConfigResolver` to streamline client secret checks based on app type.
- Enhanced logging in `OidcService` to provide detailed insights during app creation and error handling.
- Updated UI to conditionally display client secret based on app type.
- Added placeholder image support for app logos.
This commit is contained in:
= 2026-06-19 05:53:19 +00:00
parent 0b77f69818
commit 28f6da1a9a
5 changed files with 66 additions and 18 deletions

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace App\Services\Applications\OIDC;
use App\Enums\ApplicationTypeEnum;
class OidcConfigResolver
{
private ?ApplicationTypeEnum $applicationType = null;
public function for(ApplicationTypeEnum $applicationType): OidcConfigResolver
{
$this->applicationType = $applicationType;
return $this;
}
public function hasClientSecret(): bool
{
return ApplicationTypeEnum::SPA !== $this->applicationType;
}
}

View File

@ -11,6 +11,7 @@
use App\Services\{ApplicationLogoUploader, ConnectedAppService};
use App\Services\Applications\OIDC\Factory\ClientCreationFactory;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Throwable;
@ -27,6 +28,10 @@ public function __construct(
*/
public function createApp(StoreOIDCAppData $data): CreatedApplicationData
{
Log::info('Creating OIDC app', [
'name' => $data->name,
'type' => $data->type,
]);
try {
DB::beginTransaction();
$logo = $this->logoUploader->store($data->logo);
@ -47,12 +52,23 @@ public function createApp(StoreOIDCAppData $data): CreatedApplicationData
// remove sensitive data
$appData->settings = null;
Log::info('OIDC app created', [
'name' => $data->name,
'type' => $data->type,
'clientId' => isset($clientData->clientId),
'clientSecret' => isset($clientData->clientSecret),
]);
return new CreatedApplicationData(
application: $appData,
clientCredentials: $clientData,
);
} catch (Throwable $e) {
DB::rollBack();
Log::error('Failed to create OIDC app', [
'name' => $data->name,
'type' => $data->type,
]);
throw $e;
}
}

View File

@ -34,6 +34,7 @@ function () use ($data): ConnectedAppData {
$data->toArray()
);
// Create a permission for this app
$this->permissionService->add(ConnectedAppData::from($connectedApp), ConnectedAppPermissonEnum::Use);
return ConnectedAppData::from($connectedApp);

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -7,8 +7,8 @@
use App\Livewire\Concerns\Choices\{ChoiceField, WithSearchableChoices};
use App\Livewire\Concerns\WithRepeaterFields;
use App\Livewire\Forms\StoreOIDCAppForm;
use App\Services\{Applications\OIDC\OidcService, RoleService};
use Livewire\Attributes\{Url};
use App\Services\{Applications\OIDC\OidcConfigResolver, Applications\OIDC\OidcService, RoleService};
use Livewire\Attributes\{Computed, Url};
use Livewire\Component;
use Livewire\WithFileUploads;
@ -34,12 +34,14 @@ class extends Component {
public ApplicationTypeEnum $applicationType;
private RoleService $roleService;
private OidcService $oidcService;
private OidcConfigResolver $configResolver;
public function boot(RoleService $roleService, OidcService $oidcService): void
public function boot(RoleService $roleService, OidcService $oidcService, OidcConfigResolver $configResolver): void
{
$this->roleService = $roleService;
$this->oidcService = $oidcService;
$this->configResolver = $configResolver;
}
public function mount(): void
@ -60,6 +62,8 @@ public function save(bool $goBack = true): void
function () {
$data = StoreOIDCAppData::fromArray($this->applicationType, $this->form->pull());
$appdata = $this->oidcService->createApp($data);
// Show the credentials
$this->created = true;
$this->clientId = $appdata->clientCredentials->clientId;
$this->clientSecret = $appdata->clientCredentials->clientSecret;
@ -111,40 +115,43 @@ protected function choiceFields(): array
),
];
}
#[Computed]
public function hasClientSecret(): bool
{
return $this->configResolver->for($this->applicationType)->hasClientSecret();
}
};
?>
<div>
@if($created && $clientId && $clientSecret)
@if($created)
<x-shared.card
title="Application Created"
icon="lucide-check-circle"
>
<div class="flex w-full justify-center items-center pt-6">
<article class="mx-auto flex items-center gap-4">
<x-mary-avatar :image="$app->logo" alt="App logo" class="w-14! rounded-lg! p-2"/>
<x-mary-avatar :image="$app->logo ? asset($app->logo) : asset('images/app-icon-placeholder.png')"
alt="App logo"
class="w-14! rounded-lg! p-2"/>
<h1 class="text-2xl font-medium">{{$app->name}}</h1>
</article>
</div>
<div class="space-y-6 p-6">
<x-mary-alert
title="Save these credentials"
description="The client secret will only be displayed once."
class="alert-warning alert-soft text-yellow-700"
/>
<x-mary-input
label="Client ID"
:value="$clientId"
readonly
/>
<x-mary-input
label="Client Secret"
:value="$clientSecret"
readonly
@if($this->hasClientSecret)
<x-mary-alert
title="Save these credentials"
description="The client secret will only be displayed once."
class="alert-warning alert-soft text-yellow-700"
/>
<x-mary-password label="Client Secret" :value="$clientSecret" readonly right/>
@endif
<div class="flex justify-end gap-4">
<x-mary-button