createAuthScopeGateway(); $result = $authServicesFactory->createApiTokenService()->validate($bearerToken); if ($result === null) { return false; } $user = $result['user']; $userId = (int) ($user['id'] ?? 0); $userServicesFactory = new UserServicesFactory(); $userRoleRepository = $userServicesFactory->createUserRoleRepository(); $rolePermissionRepository = (new AccessServicesFactory())->createRolePermissionRepository(); $userTenantContextService = $userServicesFactory->createUserTenantContextService(); // Load permissions directly (bypass session cache) $roleIds = $userRoleRepository->listRoleIdsByUserId($userId); $permissions = $rolePermissionRepository->listPermissionKeysByRoleIds($roleIds); // Resolve tenant context $tokenTenantId = $result['tenant_id']; if ($tokenTenantId !== null) { $userTenantIds = $scopeGateway->getUserTenantIds($userId); if (!in_array($tokenTenantId, $userTenantIds, true)) { return false; } $currentTenantId = $tokenTenantId; self::$tokenTenantId = $tokenTenantId; } else { $currentTenantId = $userTenantContextService->getCurrentTenantId($userId); self::$tokenTenantId = null; } self::$currentUser = $user; self::$currentPermissions = $permissions; self::$currentTenantId = $currentTenantId; self::$currentTokenRecord = $result['token_record']; self::$authenticated = true; return true; } public static function isAuthenticated(): bool { return self::$authenticated; } public static function user(): ?array { return self::$currentUser; } public static function userId(): int { return (int) (self::$currentUser['id'] ?? 0); } public static function permissions(): array { return self::$currentPermissions ?? []; } public static function hasPermission(string $key): bool { return in_array($key, self::$currentPermissions ?? [], true); } public static function tenantId(): ?int { return self::$currentTenantId; } public static function scopedTenantId(): ?int { return self::$tokenTenantId; } public static function tokenRecord(): ?array { return self::$currentTokenRecord; } public static function tokenId(): ?int { $id = (int) (self::$currentTokenRecord['id'] ?? 0); return $id > 0 ? $id : null; } public static function isTenantScopedToken(): bool { return (self::$tokenTenantId ?? 0) > 0; } /** * Require both tenant-scope and token-tenant access for a resource. */ public static function requireResourceAccess(string $resource, int $resourceId): void { $scopeGateway = (new AuthServicesFactory())->createAuthScopeGateway(); if (!$scopeGateway->canAccess($resource, $resourceId, self::userId())) { ApiResponse::notFound(); } self::requireTokenTenantAccess($resource, $resourceId); } public static function requireTokenTenantAccess(string $resource, int $resourceId): void { if (!self::isTenantScopedToken()) { return; } $tenantId = (int) (self::$tokenTenantId ?? 0); if ($tenantId <= 0) { ApiResponse::forbidden(); } $scopeGateway = (new AuthServicesFactory())->createAuthScopeGateway(); if (!$scopeGateway->resourceBelongsToTenant($resource, $resourceId, $tenantId)) { ApiResponse::notFound(); } } /** * Check if the current user can self-manage API tokens. */ public static function canSelfManageTokens(): bool { return self::hasPermission(\MintyPHP\Service\Access\PermissionService::USERS_SELF_UPDATE) || self::hasPermission(\MintyPHP\Service\Access\PermissionService::API_TOKENS_MANAGE); } public static function requireSelfManageTokens(): void { if (!self::canSelfManageTokens()) { ApiResponse::forbidden('api_tokens_self_manage_forbidden'); } } }