Getting error 403 when going to udemy.com with c#

I am trying to get the details of my subscribed courses with the link subscribed courses (/api-2.0/users/me/subscribed-courses) using the Udemy API despite this call is not specified on the details, but when calling this on the browser it works great, however when calling the information from code I get error 403 Forbidden.
When calling for the information of a course, this works on code, and on browser.
Apparently i believe it is because of the clouflare protection.

I have the following code, where I was trying to get the accessToken to do the call after making a successful login, but i still get error 403.

{
  "udemy": {
    "Username": "[email protected]",
    "Password": "user_password",
    "Client Id": "user_client_id",
    "Client Secret": "user_client_secret",
    "LoginPage": "www.udemy.com/join/login-popup/",
    "APICoursesSubscribed": "www.udemy.com/api-2.0/users/me/subscribed-courses/",
    "APICourseDetail": "www.udemy.com/api-2.0/courses/{courseId}"
  }
}
using CloudProxySharp;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium;
using PuppeteerSharp;
using Udemy.API;

using OpenQA.Selenium.Support.UI;
using System.Collections.ObjectModel;

class Program
{
    private static APICalls  aPICalls = new APICalls();
    static async Task Main(string[] args)
    {
        //Get course details by ID
        int courseId = 120042;
        var courseDetails = await aPICalls.GetCourseAsync(courseId);
        Console.WriteLine(courseDetails.ToString());

        var subscribedCourses = await aPICalls.GetSubscribedCoursesAsync();
        Console.WriteLine(subscribedCourses.ToString());

        Puppeteer();
        await Selenium();


    }

    private static async Task Selenium()
    {
        var chromeOptions = new ChromeOptions();chromeOptions.AddArgument(
            "user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36");
        //chromeOptions.AddArgument("--remote-debugging-port=9222");
        chromeOptions.AddExcludedArgument("enable-automation");
        chromeOptions.AddAdditionalOption("useAutomationExtension", false);
        chromeOptions.AddArgument("--disable-blink-features=AutomationControlled");
        IWebDriver driver = new ChromeDriver(chromeOptions);

        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
        js.ExecuteScript("Object.defineProperty(navigator, 'webdriver', { get: () => false });");
        js.ExecuteScript("Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] });");
        js.ExecuteScript("Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });");

        driver.Navigate().GoToUrl(aPICalls.loginPage);
        Random rnd = new Random();
        int delay = rnd.Next(2000, 5000); // Random delay between 2-5 seconds
        Thread.Sleep(delay);

        ReadOnlyCollection<string> windowHandles = driver.WindowHandles;
        driver.SwitchTo().Window(windowHandles[0]);

        WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
        string element = string.Empty;
        try
        {
            element = "Cookies";
            IWebElement cookies = wait.Until(drv => drv.FindElement(By.Id("onetrust-accept-btn-handler")));
            cookies.Click();
            element = "Email";
            IWebElement email = wait.Until(drv => drv.FindElement(By.Name("email")));
            email.SendKeys(aPICalls.username);
            element = "Password";
            IWebElement password = wait.Until(drv => drv.FindElement(By.Name("password")));
            password.SendKeys(aPICalls.password);
            element = "Submit";
            IWebElement submitButton = wait.Until(drv => drv.FindElement(By.XPath("//button[@type='submit' and contains(@class, 'helpers--auth-submit-button--W3Tqk') and span[text()='Log in']]")));
            submitButton.Click();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Element {element} not found.n" + ex.Message);
        }

        driver.Quit();
    }

    private static async void Puppeteer()
    {
        var ss = await GetAccessTokenVia_Puppeteer();
        //not working for udemy
         var content = CloudProxySharpCFBypass("www.udemy.com").Result;
        CheckingHeadLessChrome().Wait();
    }

    private static async Task<string> GetAccessTokenVia_Puppeteer()
    {
        try
        {
            var options = new LaunchOptions
            {
                Headless = true,
                ExecutablePath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
            };

            using (var browser = await PuppeteerSharp.Puppeteer.LaunchAsync(options))
            using (var page = await browser.NewPageAsync())
            {
                await page.GoToAsync(aPICalls.loginPage);

                // Wait for Cloudflare challenge to complete
                await Task.Delay(10000);
                await page.WaitForSelectorAsync("input[name=email]", new WaitForSelectorOptions { Visible = true });
                await page.WaitForSelectorAsync("input[name=password]", new WaitForSelectorOptions { Visible = true });

                await page.TypeAsync("input[name=email]", aPICalls.username);
                await page.TypeAsync("input[name=password]", aPICalls.password);
                // Submit
                await page.ClickAsync("button[type=submit]");
                await Task.Delay(5000);

                var cookies = await page.GetCookiesAsync();
                foreach (var cookie in cookies)
                {
                    if (cookie.Name == "access_token")
                    {
                        return cookie.Value;
                    }
                }

                throw new Exception("Access token not found.");
            }
        } catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            throw new Exception("Access token not found.");
        }
    }

    public static Task<string> CloudProxySharpCFBypass(string url)
    {
        var handler = new ClearanceHandler("http://localhost:8191/")
        {
            //Make sure that the string literal is in single line else it won't work 
            UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
            MaxTimeout = 60000
        };

        var client = new HttpClient(handler);
        var content = client.GetStringAsync(url);
        return content;
    }
    // Just to see PuppeteerSharp in action in an headless chrome settings 
    public static async Task CheckingHeadLessChrome()
    {
        string outputFile = "Shot.png";
        var browserFetcher = new BrowserFetcher();
        await browserFetcher.DownloadAsync();
        var options = new LaunchOptions()
        {
            ExecutablePath = @"C:Program FilesGoogleChromeApplicationchrome.exe",
            Headless = false,
            SlowMo = 10
        };
        await using var browser = await PuppeteerSharp.Puppeteer.LaunchAsync(options);
        await using var page = await browser.NewPageAsync();
        await page.GoToAsync("www.udemy.com");
        
        var allContent = await page.GetContentAsync();
        var cookies = page.GetCookiesAsync();
        await page.GoToAsync("www.udemy.com");
    }
}
using Newtonsoft.Json.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
using System.Text.RegularExpressions;

namespace Udemy.API
{
    class APICalls
    {
        string credentialsFilePath = "res\udemyCredentials.json";
        public string clientId;
        public string clientSecret;
        public string APICoursesSubscribed;
        public string APICourseDetail;
        public string username;
        public string password;
        public string loginPage;
        public string accessToken;

        public APICalls()
        {
            // Read and parse the JSON file
            var credentials = ReadCredentials(credentialsFilePath);

            this.clientId = credentials["Client Id"].ToString();
            this.clientSecret = credentials["Client Secret"].ToString();
            this.APICoursesSubscribed = credentials["APICoursesSubscribed"].ToString();
            this.APICourseDetail = credentials["APICourseDetail"].ToString();
            this.username = credentials["Username"].ToString();
            this.password = credentials["Password"].ToString();
            this.loginPage = credentials["LoginPage"].ToString();

            // Log in to Udemy and get the access token
            this.accessToken = GetAccessTokenViaLogin().Result;
        }

        static JObject ReadCredentials(string filePath)
        {
            using (StreamReader reader = new StreamReader(filePath))
            {
                string json = reader.ReadToEnd();
                JObject credentials = JObject.Parse(json);
                return (JObject)credentials["udemy"];
            }
        }


        private async Task<string> GetAccessTokenViaLogin()
        {
            using (HttpClientHandler handler = new HttpClientHandler { UseCookies = true })
            using (HttpClient client = new HttpClient(handler))
            {
                // Step 1: Get the CSRF token from the login page
                HttpResponseMessage getLoginPageResponse = await client.GetAsync("https://www.udemy.com/join/login-popup/");
                string loginPageContent = await getLoginPageResponse.Content.ReadAsStringAsync();

                // Extract the CSRF token from the login page content
                var csrfToken = ExtractCsrfToken(loginPageContent);
                if (csrfToken == null)
                {
                    Console.WriteLine("CSRF token not found.");
                    return null;
                }

                var requestBody = new MultipartFormDataContent
                {
                    { new StringContent(username), "email" },
                    { new StringContent(password), "password" },
                    { new StringContent(csrfToken), "csrfmiddlewaretoken" }
                };

                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36");
                client.DefaultRequestHeaders.Add("Origin", "https://www.udemy.com");
                client.DefaultRequestHeaders.Add("Referer", aPICalls.loginPage+"/?locale=en_US&response_type=html&next=https%3A%2F%2Fwww.udemy.com%2Flogout%2F");

                HttpResponseMessage response = await client.PostAsync(aPICalls.loginPage+"/?locale=en_US&next=https%3A%2F%2Fwww.udemy.com%2Flogout%2F&response_type=html&response_type=json", requestBody);

                if (response.IsSuccessStatusCode)
                {
                    string content = await response.Content.ReadAsStringAsync();
                    // Print the response for debugging purposes
                    Console.WriteLine(content);

                    // Attempt to extract the access token from cookies if available
                    foreach (Cookie cookie in handler.CookieContainer.GetCookies(new Uri("https://www.udemy.com")))
                    {
                        if (cookie.Name == "access_token")
                        {
                            return cookie.Value;
                        }
                    }

                    // If the token is not in the cookies, check the response body
                    JObject jsonResponse = JObject.Parse(content);
                    if (jsonResponse.ContainsKey("access_token"))
                    {
                        return jsonResponse["access_token"].ToString();
                    }
                }
                else
                {
                    Console.WriteLine($"Error obtaining access token: {response.StatusCode}");
                }

                return null;
            }
        }

        private string ExtractCsrfToken(string htmlContent)
        {
            // This is a simple example, you might need to adjust it to match the actual HTML structure
            var csrfTokenStart = htmlContent.IndexOf("csrfmiddlewaretoken") + 22;
            var csrfTokenEnd = htmlContent.IndexOf(""", csrfTokenStart);
            if (csrfTokenStart > -1 && csrfTokenEnd > -1)
            {
                return htmlContent.Substring(csrfTokenStart, csrfTokenEnd - csrfTokenStart);
            }
            return null;
        }

        public async Task<JObject> GetSubscribedCoursesAsync()
        {
            return await GetPage(APICoursesSubscribed);
        }
        
        public async Task<JObject> GetCourseAsync(int courseId)
        {
            string url = APICourseDetail.Replace("{courseId}", courseId.ToString());

            return await GetPage(url);
        }
        public async Task<JObject> GetPage(string url)
        {
            string encodedClientId = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientId));
            string encodedClientSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes(clientSecret));
            string authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));

            HttpClientHandler handler = new HttpClientHandler();
            handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;

            using (HttpClient customClient = new HttpClient(handler))
            {
                customClient.DefaultRequestHeaders.Accept.Clear();
                customClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                customClient.DefaultRequestHeaders.Add("X-Udemy-Client-Id", encodedClientId);
                customClient.DefaultRequestHeaders.Add("X-Udemy-Client-Secret", encodedClientSecret);
                customClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authHeader);

                HttpResponseMessage response = await customClient.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    string result = await response.Content.ReadAsStringAsync();
                    return JObject.Parse(result);
                }
                else
                {
                    Console.WriteLine($"Error: {response.StatusCode} ({(int)response.StatusCode})");

                    return null;
                }
            }
        }
    }
}

I tried using Selenium, but upon filling the email and password field i would get an unkown error on udemy login page, and on the console shows severar 403 errors.
I tried using Puppeteer-Sharp, and CloudProxySharp as described here, but no luck either

New contributor

rc vf is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật