Skip to content

Commit 8f70f57

Browse files
committed
feat(javascript): add a isRecognizedBaseUrlPattern util
1 parent 03f32c6 commit 8f70f57

File tree

3 files changed

+132
-0
lines changed

3 files changed

+132
-0
lines changed

packages/javascript/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export {default as processUsername} from './utils/processUsername';
135135
export {default as deepMerge} from './utils/deepMerge';
136136
export {default as deriveOrganizationHandleFromBaseUrl} from './utils/deriveOrganizationHandleFromBaseUrl';
137137
export {default as extractUserClaimsFromIdToken} from './utils/extractUserClaimsFromIdToken';
138+
export {default as isRecognizedBaseUrlPattern} from './utils/isRecognizedBaseUrlPattern';
138139
export {default as extractPkceStorageKeyFromState} from './utils/extractPkceStorageKeyFromState';
139140
export {default as flattenUserSchema} from './utils/flattenUserSchema';
140141
export {default as generateUserProfile} from './utils/generateUserProfile';
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
import {describe, it, expect, vi} from 'vitest';
20+
import isRecognizedBaseUrlPattern from '../isRecognizedBaseUrlPattern';
21+
import AsgardeoRuntimeError from '../../errors/AsgardeoRuntimeError';
22+
23+
vi.mock('../logger', () => ({default: {warn: vi.fn()}}));
24+
25+
describe('isRecognizedBaseUrlPattern', () => {
26+
it('returns true for recognized Asgardeo base URL pattern', () => {
27+
expect(isRecognizedBaseUrlPattern('https://dev.asgardeo.io/t/dxlab')).toBe(true);
28+
expect(isRecognizedBaseUrlPattern('https://example.com/t/org')).toBe(true);
29+
expect(isRecognizedBaseUrlPattern('https://foo.com/t/bar/')).toBe(true);
30+
expect(isRecognizedBaseUrlPattern('https://foo.com/t/bar/extra')).toBe(true);
31+
});
32+
33+
it('returns false for unrecognized base URL pattern', () => {
34+
expect(isRecognizedBaseUrlPattern('https://dev.asgardeo.io/tenant/dxlab')).toBe(false);
35+
expect(isRecognizedBaseUrlPattern('https://dev.asgardeo.io/')).toBe(false);
36+
expect(isRecognizedBaseUrlPattern('https://dev.asgardeo.io/t')).toBe(false);
37+
expect(isRecognizedBaseUrlPattern('https://dev.asgardeo.io/other/path')).toBe(false);
38+
});
39+
40+
it('throws AsgardeoRuntimeError if baseUrl is undefined', () => {
41+
expect(() => isRecognizedBaseUrlPattern(undefined)).toThrow(AsgardeoRuntimeError);
42+
43+
try {
44+
isRecognizedBaseUrlPattern(undefined);
45+
} catch (e: any) {
46+
expect(e).toBeInstanceOf(AsgardeoRuntimeError);
47+
expect(e.message).toMatch(/Base URL is required/);
48+
}
49+
});
50+
51+
it('throws AsgardeoRuntimeError for invalid URL format', () => {
52+
expect(() => isRecognizedBaseUrlPattern('not-a-valid-url')).toThrow(AsgardeoRuntimeError);
53+
54+
try {
55+
isRecognizedBaseUrlPattern('not-a-valid-url');
56+
} catch (e: any) {
57+
expect(e).toBeInstanceOf(AsgardeoRuntimeError);
58+
expect(e.message).toMatch(/Invalid base URL format/);
59+
}
60+
});
61+
});
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). All Rights Reserved.
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
import AsgardeoRuntimeError from "../errors/AsgardeoRuntimeError";
20+
import logger from "./logger";
21+
22+
/**
23+
* Utility to determine if sensible Asgardeo fallbacks can be used based on the given base URL.
24+
*
25+
* This checks if the URL follows the standard Asgardeo pattern: /t/{orgHandle}
26+
* Returns true if sensible fallbacks (like deriving organization handle, tenant, etc.) can be used, false otherwise.
27+
*
28+
* @param baseUrl - The base URL of the Asgardeo identity server (string or undefined)
29+
* @returns boolean - true if sensible fallbacks can be used, false otherwise
30+
*
31+
* @example
32+
* isRecognizedBaseUrlPattern('https://dev.asgardeo.io/t/dxlab'); // true
33+
* isRecognizedBaseUrlPattern('https://custom.example.com/auth'); // false
34+
*/
35+
const isRecognizedBaseUrlPattern = (baseUrl: string | undefined): boolean => {
36+
if (!baseUrl) {
37+
throw new AsgardeoRuntimeError(
38+
'Base URL is required to derive if the `baseUrl` is recognized.',
39+
'isRecognizedBaseUrlPattern-ValidationError-001',
40+
'javascript',
41+
'A valid base URL must be provided to derive if the `baseUrl` is recognized to use the sensible fallbacks.',
42+
);
43+
}
44+
45+
let parsedUrl: URL;
46+
47+
try {
48+
parsedUrl = new URL(baseUrl);
49+
} catch (error) {
50+
throw new AsgardeoRuntimeError(
51+
`Invalid base URL format: ${baseUrl}`,
52+
'isRecognizedBaseUrlPattern-ValidationError-002',
53+
'javascript',
54+
'The provided base URL does not conform to valid URL syntax.',
55+
);
56+
}
57+
58+
// Extract the organization handle from the path pattern: /t/{orgHandle}
59+
const pathSegments = parsedUrl.pathname?.split('/')?.filter(segment => segment?.length > 0);
60+
61+
if (pathSegments.length < 2 || pathSegments[0] !== 't') {
62+
logger.warn('[isRecognizedBaseUrlPattern] The provided base URL does not follow the expected URL pattern (/t/{orgHandle}).');
63+
64+
return false;
65+
}
66+
67+
return true;
68+
};
69+
70+
export default isRecognizedBaseUrlPattern;

0 commit comments

Comments
 (0)