diff --git a/.changeset/olive-stingrays-share.md b/.changeset/olive-stingrays-share.md
new file mode 100644
index 0000000000000000000000000000000000000000..af0d69721729c2e5333eb71cda4095748013c268
--- /dev/null
+++ b/.changeset/olive-stingrays-share.md
@@ -0,0 +1,5 @@
+---
+"@rocket.chat/cas-validate": patch
+---
+
+Fixes a problem with CAS when URL connection ended with `/`
diff --git a/packages/cas-validate/jest.config.ts b/packages/cas-validate/jest.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..90df717c7694523ba744995b986c4de66b37ffc2
--- /dev/null
+++ b/packages/cas-validate/jest.config.ts
@@ -0,0 +1,12 @@
+import server from '@rocket.chat/jest-presets/server';
+import type { Config } from 'jest';
+
+export default {
+	projects: [
+		{
+			displayName: 'server',
+			preset: server.preset,
+			testMatch: ['<rootDir>/src/**/*.spec.[jt]s?(x)'],
+		},
+	],
+} satisfies Config;
diff --git a/packages/cas-validate/package.json b/packages/cas-validate/package.json
index 5c21ecfa41d4640571b6f6e2cb1e0eff5b3109b5..0a005a4d8cb9058dcfb9729281b15d52f9372953 100644
--- a/packages/cas-validate/package.json
+++ b/packages/cas-validate/package.json
@@ -11,7 +11,8 @@
 		"lint": "eslint --ext .js,.jsx,.ts,.tsx .",
 		"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix",
 		"build": "rm -rf dist && tsc -p tsconfig.json",
-		"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput"
+		"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
+		"testunit": "jest"
 	},
 	"main": "./dist/index.js",
 	"typings": "./dist/index.d.ts",
@@ -19,6 +20,7 @@
 		"/dist"
 	],
 	"dependencies": {
-		"cheerio": "1.0.0"
+		"cheerio": "1.0.0",
+		"jest": "^29.7.0"
 	}
 }
diff --git a/packages/cas-validate/src/validate.spec.ts b/packages/cas-validate/src/validate.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5fab05761532c0ba6c01b30c3094a36fb341393d
--- /dev/null
+++ b/packages/cas-validate/src/validate.spec.ts
@@ -0,0 +1,53 @@
+import { getQueryPath } from './validate';
+
+describe('getQueryPath', () => {
+	it('should generate the correct query path without trailing slash', () => {
+		const partialPathname = '/cas';
+		const validatePath = 'validate';
+		const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
+
+		const result = getQueryPath(partialPathname, validatePath, query);
+
+		expect(result).toBe('/cas/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
+	});
+
+	it('should generate the correct query path with trailing slash', () => {
+		const partialPathname = '/cas/';
+		const validatePath = 'validate';
+		const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
+
+		const result = getQueryPath(partialPathname, validatePath, query);
+
+		expect(result).toBe('/cas/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
+	});
+
+	it('should generate the correct query path with `/` partialPathname', () => {
+		const partialPathname = '/';
+		const validatePath = 'validate';
+		const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
+
+		const result = getQueryPath(partialPathname, validatePath, query);
+
+		expect(result).toBe('/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
+	});
+
+	it('should generate the correct query path with empty partialPathname', () => {
+		const partialPathname = '';
+		const validatePath = 'validate';
+		const query = { ticket: 'ST-12345', service: 'https://myapp.com' };
+
+		const result = getQueryPath(partialPathname, validatePath, query);
+
+		expect(result).toBe('/validate?ticket=ST-12345&service=https%3A%2F%2Fmyapp.com');
+	});
+
+	it('should generate the correct query path with empty query', () => {
+		const partialPathname = '/cas';
+		const validatePath = 'validate';
+		const query = {};
+
+		const result = getQueryPath(partialPathname, validatePath, query);
+
+		expect(result).toBe('/cas/validate');
+	});
+});
diff --git a/packages/cas-validate/src/validate.ts b/packages/cas-validate/src/validate.ts
index cef47a50a230016c03087dc60d1524eb6b53824d..44cb86676671b5101cc2c673302be63faa3a19a7 100644
--- a/packages/cas-validate/src/validate.ts
+++ b/packages/cas-validate/src/validate.ts
@@ -1,5 +1,6 @@
 import type { IncomingMessage } from 'http';
 import https from 'https';
+import type { ParsedUrlQueryInput } from 'querystring';
 import url from 'url';
 
 import type { Cheerio, CheerioAPI } from 'cheerio';
@@ -149,6 +150,19 @@ function parseAttributes(elemSuccess: Cheerio<any>, cheerio: CheerioAPI): Record
 	return attributes;
 }
 
+export function getQueryPath(
+	partialPathname: string,
+	validatePath: string,
+	query: string | ParsedUrlQueryInput | null | undefined,
+): string {
+	const pathname = partialPathname?.endsWith('/') ? partialPathname + validatePath : `${partialPathname}/${validatePath}`;
+
+	return url.format({
+		pathname,
+		query,
+	});
+}
+
 export function validate(options: CasOptions, ticket: string, callback: CasCallback, renew = false): void {
 	if (!options.base_url) {
 		throw new Error('Required CAS option `base_url` missing.');
@@ -176,10 +190,7 @@ export function validate(options: CasOptions, ticket: string, callback: CasCallb
 		...(renew ? { renew: 1 } : {}),
 	};
 
-	const queryPath = url.format({
-		pathname: `${pathname}/${validatePath}`,
-		query,
-	});
+	const queryPath = getQueryPath(pathname ?? '/', validatePath, query);
 
 	const req = https.get(
 		{
diff --git a/yarn.lock b/yarn.lock
index 40b92d6b52beefb2aba16352d7f57b9c208180f5..3596ddbc6cb5b2946ab81472606cb3ddbf57aaae 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7566,6 +7566,7 @@ __metadata:
   dependencies:
     cheerio: "npm:1.0.0"
     eslint: "npm:~8.45.0"
+    jest: "npm:^29.7.0"
     typescript: "npm:~5.7.2"
   languageName: unknown
   linkType: soft