I'm trying to automate a search on the Texas Parks & Wildlife Department's TORA (Boat/Motor Ownership Inquiry) system using C# and RestSharp. While I can successfully navigate through the initial steps (getting session tokens and accepting terms), my final POST request to search for a company just returns the same requester page instead of any search results. I am able to do the first https://apps.tpwd.state.tx.us/tora/legal.jsf Here is the final webpage that I have issues with https://apps.tpwd.state.tx.us/tora/requester.jsf
Here's what I've implemented so far:
// Step 1: Initial GET request to retrieve the page and cookies
Console.WriteLine("Hello, World!");
var options = new RestClientOptions("https://apps.tpwd.state.tx.us")
{
MaxTimeout = -1,
};
var client = new RestClient(options);
// Step 1: Get JSESSIONID
var initRequest = new RestRequest("/tora/legal.jsf", Method.Get);
var initResponse = await client.ExecuteAsync(initRequest);
var jsessionId = initResponse.Cookies
.FirstOrDefault(c => c.Name == "JSESSIONID")?.Value;
if (string.IsNullOrEmpty(jsessionId))
{
Console.WriteLine("Failed to retrieve JSESSIONID");
return;
}
else
{
Console.WriteLine("jsessionId: " + jsessionId);
}
// Load the HTML content into HtmlAgilityPack
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(initResponse.Content);
Console.WriteLine(initResponse.Content);
// Extract the _csrf token and javax.faces.ViewState
var csrfTokenNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='_csrf']");
var viewStateNode = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='javax.faces.ViewState']");
string csrfToken = string.Empty;
string viewState = string.Empty;
if (csrfTokenNode != null && viewStateNode != null)
{
csrfToken = csrfTokenNode.GetAttributeValue("value", string.Empty);
viewState = viewStateNode.GetAttributeValue("value", string.Empty);
Console.WriteLine("CSRF Token: " + csrfToken);
Console.WriteLine("ViewState: " + viewState);
}
else
{
Console.WriteLine("CSRF token or ViewState not found!");
}
// Step 2: Accept Terms (POST to /tora/legal.jsf)
var acceptRequest = new RestRequest("/tora/legal.jsf", Method.Post);
acceptRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded");
acceptRequest.AddHeader("Cookie", $"JSESSIONID={jsessionId}");
acceptRequest.AddParameter("form", "form");
acceptRequest.AddParameter("form:accept", "Accept");
acceptRequest.AddParameter("form:_idcl", "");
acceptRequest.AddParameter("_csrf", csrfToken);
acceptRequest.AddParameter("javax.faces.ViewState", viewState);
var acceptResponse = await client.ExecuteAsync(acceptRequest);
if (!acceptResponse.IsSuccessful)
{
Console.WriteLine("Failed to accept terms.");
return;
}
else
{
Console.WriteLine("acceptResponse: " + acceptResponse.Content);
}
var ssm_au_c = acceptResponse.Cookies
.FirstOrDefault(c => c.Name == "ssm_au_c")?.Value;
var pkCookieID = acceptResponse.Cookies
.FirstOrDefault(c => c.Name == "_pk_id.9.df1b")?.Value;
var pkCookieSes = acceptResponse.Cookies
.FirstOrDefault(c => c.Name == "_pk_ses.9.df1b")?.Value;
Console.WriteLine("ssm_au_c " + ssm_au_c);
Console.WriteLine("pkCookieID " + pkCookieID);
Console.WriteLine("pkCookieSes " + pkCookieSes);
// Step 3: GET the requester.faces page to get new tokens
var getRequesterPage = new RestRequest("/tora/requester.faces", Method.Get);
getRequesterPage.AddHeader("Cookie", $"JSESSIONID={jsessionId}");
var requesterResponse = await client.ExecuteAsync(getRequesterPage);
// Get new tokens from the requester page
var requesterDoc = new HtmlDocument();
requesterDoc.LoadHtml(requesterResponse.Content);
var newCsrfToken = requesterDoc.DocumentNode.SelectSingleNode("//input[@name='_csrf']")?.GetAttributeValue("value", string.Empty);
var newViewState = requesterDoc.DocumentNode.SelectSingleNode("//input[@name='javax.faces.ViewState']")?.GetAttributeValue("value", string.Empty);
if (string.IsNullOrEmpty(newCsrfToken) || string.IsNullOrEmpty(newViewState))
{
Console.WriteLine("Failed to get new tokens from requester page");
return;
}
// Now update your final POST request to use the new tokens
var request = new RestRequest("/tora/requester.faces", Method.Post);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Cookie", $"JSESSIONID={jsessionId}");
request.AddHeader("Referer", "https://apps.tpwd.state.tx.us/tora/requester.faces");
// Basic form parameters
request.AddParameter("form", "form");
request.AddParameter("form:hasCompany", "true");
request.AddParameter("form:company", "Texans Credit Union");
request.AddParameter("form:address1", "777 E Campbell Rd");
request.AddParameter("form:city", "Richardson");
request.AddParameter("form:state", "TX");
request.AddParameter("form:zip", "75081");
request.AddParameter("form:search", "Search");
request.AddParameter("_csrf", newCsrfToken);
request.AddParameter("javax.faces.ViewState", newViewState);
// Add these JSF-specific parameters
request.AddParameter("javax.faces.partial.ajax", "true");
request.AddParameter("javax.faces.source", "form:search");
request.AddParameter("javax.faces.partial.execute", "@all");
request.AddParameter("javax.faces.partial.render", "@all");
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
var response = await client.ExecuteAsync(request);
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("Final Response:");
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine(response.Content);
if (response.Content.Contains("Vessel/Boat "))
{
Console.WriteLine("The string contains 'Vessel/Boat '.");
}
else
{
Console.WriteLine("The string does not contain 'Vessel/Boat '.");
}
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Request failed with status code: {response.StatusCode}");
Console.WriteLine($"Response content: {response.Content}");
}
Console.WriteLine("end program");
When I submit this request, instead of getting search results, I just get back the same requester.faces page HTML. The actual website (https://apps.tpwd.state.tx.us/tora/requester.jsf) works fine when used manually through a browser.
What I've tried:
What am I missing in my POST request to get actual search results instead of just getting the same page back?
Environment:
I also was able to do the post call through postman.
Im not sure what i am doing wrong....
Any help would be greatly appreciated!
I changed up some of the headers using postman/fiddler/etc. Also, I did the same http post twice in a row and it passes to the next page. Not sure why.
So it's working now...
Here is the updated code:
var request4 = new RestRequest("/tora/requester.jsf", Method.Post);
request4.AddHeader("Host", "apps.tpwd.state.tx.us");
request4.AddHeader("Connection", "keep-alive");
request4.AddHeader("Cache-Control", "max-age=0");
request4.AddHeader("sec-ch-ua", "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Google Chrome\";v=\"134\"");
request4.AddHeader("sec-ch-ua-mobile", "?0");
request4.AddHeader("sec-ch-ua-platform", "\"Windows\"");
request4.AddHeader("Origin", "https://apps.tpwd.state.tx.us");
request4.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request4.AddHeader("Upgrade-Insecure-Requests", "1");
request4.AddHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36");
request4.AddHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
request4.AddHeader("Sec-Fetch-Site", "same-origin");
request4.AddHeader("Sec-Fetch-Mode", "navigate");
request4.AddHeader("Sec-Fetch-User", "?1");
request4.AddHeader("Sec-Fetch-Dest", "document");
request4.AddHeader("Referer", "https://apps.tpwd.state.tx.us/tora/requester.jsf");
request4.AddHeader("Accept-Encoding", "gzip, deflate, br, zstd");
request4.AddHeader("Accept-Language", "en-US,en;q=0.9");
AddCookies(request4);
request4.AddParameter("form", "form");
request4.AddParameter("_csrf", csrfToken);
request4.AddParameter("hasCompany", "true");
request4.AddParameter("foreign", "false");
request4.AddParameter("company", "TEXANS CREDIT UNION");
request4.AddParameter("address1", "777 E CAMPBELL RD");
request4.AddParameter("address2", "");
request4.AddParameter("city", "RICHARDSON");
request4.AddParameter("state", "TX");
request4.AddParameter("zip", "75081");
request4.AddParameter("javax.faces.ViewState", viewState);
request4.AddParameter("search", "search");
var response4 = await _client.ExecuteAsync(request4);
if (response4.IsSuccessful)
{
Console.WriteLine("POST requester.jsf successful");
Console.WriteLine(response4.Content); // Display the content for inspection
ParseCookies(response4);
}
else
{
Console.WriteLine($"POST requester.jsf failed: {response4.ErrorMessage}");
}
var response4Again = await _client.ExecuteAsync(request4);
if (response4Again.IsSuccessful)
{
Console.WriteLine("POST requester.jsf successful");
Console.WriteLine(response4.Content); // Display the content for inspection
ParseCookies(response4);
}
else
{
Console.WriteLine($"POST requester.jsf failed: {response4.ErrorMessage}");
}