Files
server/shared/lib/Security/Authentication/ProviderResult.php
2026-02-10 18:46:11 -05:00

157 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
namespace KTXF\Security\Authentication;
/**
* Provider Result
*
* Result returned from authentication providers.
* Separates client-facing data from session persistence data.
*/
readonly class ProviderResult
{
// Status constants
public const SUCCESS = 'success';
public const FAILED = 'failed';
public const CHALLENGE = 'challenge';
public const REDIRECT = 'redirect';
// Error codes
public const ERROR_INVALID_CREDENTIALS = 'invalid_credentials';
public const ERROR_INVALID_PROVIDER = 'invalid_provider';
public const ERROR_INVALID_FACTOR = 'invalid_factor';
public const ERROR_FACTOR_FAILED = 'factor_failed';
public const ERROR_NOT_ENROLLED = 'not_enrolled';
public const ERROR_RATE_LIMITED = 'rate_limited';
public const ERROR_INTERNAL = 'internal_error';
public function __construct(
/** Result status */
public string $status,
/** Error code for failures */
public ?string $errorCode = null,
/** Human-readable error message */
public ?string $errorMessage = null,
/** Verified identity claims (user_id, provider, etc.) */
public array $identity = [],
/** Data to send to client (challenge info, redirect URL, etc.) */
public array $clientData = [],
/** Data to persist in session for subsequent calls */
public array $sessionData = [],
) {}
// =========================================================================
// Factory Methods
// =========================================================================
/**
* Create a success result
*/
public static function success(array $identity = [], array $clientData = [], array $sessionData = []): self
{
return new self(
status: self::SUCCESS,
identity: $identity,
clientData: $clientData,
sessionData: $sessionData,
);
}
/**
* Create a failed result
*/
public static function failed(
string $errorCode = self::ERROR_INVALID_CREDENTIALS,
?string $errorMessage = null
): self {
return new self(
status: self::FAILED,
errorCode: $errorCode,
errorMessage: $errorMessage,
);
}
/**
* Create a challenge result (for challenge-based auth)
*/
public static function challenge(array $challengeInfo, array $sessionData = []): self
{
return new self(
status: self::CHALLENGE,
clientData: ['challenge' => $challengeInfo],
sessionData: $sessionData,
);
}
/**
* Create a redirect result (for OIDC/SAML)
*/
public static function redirect(string $url, array $sessionData): self
{
return new self(
status: self::REDIRECT,
clientData: ['redirect_url' => $url],
sessionData: $sessionData,
);
}
// =========================================================================
// Status Checks
// =========================================================================
public function isSuccess(): bool
{
return $this->status === self::SUCCESS;
}
public function isFailed(): bool
{
return $this->status === self::FAILED;
}
public function isChallenge(): bool
{
return $this->status === self::CHALLENGE;
}
public function isRedirect(): bool
{
return $this->status === self::REDIRECT;
}
// =========================================================================
// Data Access
// =========================================================================
/**
* Get identity claim
*/
public function getIdentity(string $key, mixed $default = null): mixed
{
return $this->identity[$key] ?? $default;
}
/**
* Get client data value
*/
public function getClientData(string $key, mixed $default = null): mixed
{
return $this->clientData[$key] ?? $default;
}
/**
* Get session data value
*/
public function getSessionData(string $key, mixed $default = null): mixed
{
return $this->sessionData[$key] ?? $default;
}
}