state; } /** * Check if session has expired */ public function isExpired(): bool { return time() > $this->expiresAt; } /** * Check if session is in initial state */ public function isFresh(): bool { return $this->state === self::STATE_FRESH; } /** * Check if session has identity but awaiting authentication */ public function isIdentified(): bool { return $this->state === self::STATE_IDENTIFIED; } /** * Check if session is in the process of authenticating */ public function isAuthenticating(): bool { return $this->state === self::STATE_AUTHENTICATING; } /** * Check if session is complete */ public function isComplete(): bool { return $this->state === self::STATE_COMPLETE; } /** * Set user identity (before authentication) */ public function setIdentity(string $value): void { $this->userIdentity = $value; $this->state = self::STATE_IDENTIFIED; } public function setMethods(array $methods, int $require = 1): void { $this->methodsAvailable = $methods; $this->methodsRequired = $require; } public function methodEligible(string $method): bool { return in_array($method, $this->methodsAvailable, true) && !in_array($method, $this->methodsCompleted, true); } /** * Mark a method as completed */ public function methodCompleted(string $method): void { if (!in_array($method, $this->methodsCompleted, true)) { $this->methodsCompleted[] = $method; } // If we have required factors and all are complete, mark session complete if (count($this->methodsCompleted) >= $this->methodsRequired) { $this->state = self::STATE_COMPLETE; } } /** * Get methods that still need to be completed */ public function methodsRemaining(): array { return array_values(array_diff($this->methodsAvailable, $this->methodsCompleted)); } /** * Promote session after successful primary auth (set user info) */ public function setUser(string $userIdentifier, string $userIdentity): void { $this->userIdentifier = $userIdentifier; $this->userIdentity = $userIdentity; } /** * Get metadata value */ public function getMeta(string $key, mixed $default = null): mixed { return $this->metadata[$key] ?? $default; } /** * Set metadata value */ public function setMeta(string $key, mixed $value): void { $this->metadata[$key] = $value; } /** * Serialize to array for storage */ public function toArray(): array { return [ 'id' => $this->id, 'state' => $this->state, 'tenant_identifier' => $this->tenantIdentifier, 'user_identifier' => $this->userIdentifier, 'user_identity' => $this->userIdentity, 'methods_required' => $this->methodsRequired, 'methods_available' => $this->methodsAvailable, 'methods_completed' => $this->methodsCompleted, 'metadata' => $this->metadata, 'created_at' => $this->createdAt, 'expires_at' => $this->expiresAt, ]; } /** * Deserialize from array */ public static function fromArray(array $data): self { return new self( id: $data['id'], state: $data['state'], tenantIdentifier: $data['tenant_identifier'], userIdentifier: $data['user_identifier'] ?? null, userIdentity: $data['user_identity'] ?? null, methodsRequired: $data['methods_required'] ?? 1, methodsAvailable: $data['methods_available'] ?? [], methodsCompleted: $data['methods_completed'] ?? [], metadata: $data['metadata'] ?? [], createdAt: $data['created_at'], expiresAt: $data['expires_at'], ); } }