Skip to content

Commit e53d6d9

Browse files
committed
Expose OIDC discovery response
1 parent 2be8430 commit e53d6d9

10 files changed

Lines changed: 218 additions & 11 deletions

File tree

.changeset/better-towns-teach.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@asgardeo/javascript': minor
3+
'@asgardeo/react': minor
4+
---
5+
6+
Expose OIDC discovery response from `useAsgardeo`

packages/javascript/src/AsgardeoJavaScriptClient.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
EmbeddedSignInFlowInitiateResponse,
3939
EmbeddedSignInFlowStatus,
4040
} from './models/embedded-signin-flow';
41+
import {OIDCDiscoveryApiResponse} from './models/oidc-discovery';
4142
import {AllOrganizationsApiResponse, Organization} from './models/organization';
4243
import {Storage} from './models/store';
4344
import {TokenExchangeRequestConfig, TokenResponse} from './models/token';
@@ -68,6 +69,14 @@ class AsgardeoJavaScriptClient<T = Config> implements AsgardeoClient<T> {
6869
this.baseURL = config?.baseUrl ?? '';
6970
}
7071

72+
public async getDiscoveryResponse(): Promise<OIDCDiscoveryApiResponse | null> {
73+
if (!this.storageManager) {
74+
return null;
75+
}
76+
77+
return this.storageManager.loadOpenIDProviderConfiguration();
78+
}
79+
7180
/* eslint-disable class-methods-use-this, @typescript-eslint/no-unused-vars */
7281
switchOrganization(_organization: Organization, _sessionId?: string): Promise<TokenResponse | Response> {
7382
throw new Error('Method not implemented.');

packages/javascript/src/__legacy__/client.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
import {AuthenticationHelper} from './helpers';
2020
import {AuthClientConfig, StrictAuthClientConfig} from './models';
2121
import OIDCDiscoveryConstants from '../constants/OIDCDiscoveryConstants';
22-
import OIDCRequestConstants from '../constants/OIDCRequestConstants';
2322
import PKCEConstants from '../constants/PKCEConstants';
23+
import OIDCRequestConstants from '../constants/OIDCRequestConstants';
24+
import OIDCDiscoveryConstantsV2 from '../constants/v2/OIDCDiscoveryConstants';
2425
import {AsgardeoAuthException} from '../errors/exception';
2526
import {IsomorphicCrypto} from '../IsomorphicCrypto';
2627
import {Crypto} from '../models/crypto';
2728
import {ExtendedAuthorizeRequestUrlParams} from '../models/oauth-request';
2829
import {OIDCDiscoveryApiResponse} from '../models/oidc-discovery';
2930
import {OIDCEndpoints} from '../models/oidc-endpoints';
31+
import {Platform} from '../models/platforms';
3032
import {SessionData, UserSession} from '../models/session';
3133
import {Storage, TemporaryStore} from '../models/store';
3234
import {TokenResponse, IdToken, TokenExchangeRequestConfig} from '../models/token';
@@ -149,7 +151,8 @@ export class AsgardeoAuthClient<T> {
149151
// Ref: https://github.com/asgardeo/asgardeo-auth-js-core/pull/205
150152
AsgardeoAuthClient.authHelperInstance = this.authHelper;
151153

152-
let {applicationId} = config;
154+
const {applicationId, platform, endpoints} = config;
155+
let resolvedApplicationId: string | undefined = applicationId;
153156

154157
if (applicationId) {
155158
await this.storageManager.setPersistedData({
@@ -159,14 +162,23 @@ export class AsgardeoAuthClient<T> {
159162
const persistedData: TemporaryStore = await this.storageManager.getPersistedData();
160163

161164
if (persistedData['applicationId']) {
162-
applicationId = persistedData['applicationId'] as string;
165+
resolvedApplicationId = persistedData['applicationId'] as string;
166+
}
167+
}
168+
169+
const resolvedEndpoints: Partial<OIDCEndpoints> = endpoints || {};
170+
171+
if (platform === Platform.AsgardeoV2) {
172+
if (!resolvedEndpoints['wellKnown']) {
173+
resolvedEndpoints['wellKnown'] = OIDCDiscoveryConstantsV2.Endpoints.WELL_KNOWN;
163174
}
164175
}
165176

166177
await this.storageManager.setConfigData({
167178
...DefaultConfig,
168179
...config,
169-
applicationId,
180+
applicationId: resolvedApplicationId,
181+
endpoints: resolvedEndpoints,
170182
scope: processOpenIDScopes(config.scopes),
171183
});
172184
}
@@ -434,13 +446,19 @@ export class AsgardeoAuthClient<T> {
434446
return Promise.resolve();
435447
}
436448

437-
const {wellKnownEndpoint} = configData as any;
449+
const {wellKnownEndpoint, platform, discovery, baseUrl, endpoints} = configData as any;
450+
451+
const resolvedWellKnownEndpoint: string | undefined =
452+
wellKnownEndpoint ||
453+
(platform === Platform.AsgardeoV2 && discovery?.wellKnown?.enabled
454+
? `${baseUrl}${endpoints?.wellKnown ?? '/.well-known/openid-configuration'}`
455+
: undefined);
438456

439-
if (wellKnownEndpoint) {
457+
if (resolvedWellKnownEndpoint) {
440458
let response: Response;
441459

442460
try {
443-
response = await fetch(wellKnownEndpoint);
461+
response = await fetch(resolvedWellKnownEndpoint);
444462
if (response.status !== 200 || !response.ok) {
445463
throw new Error();
446464
}

packages/javascript/src/__legacy__/models/client-config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import {OAuthResponseMode} from '../../models/oauth-response';
2020
import {OIDCEndpoints} from '../../models/oidc-endpoints';
21+
import {Platform} from '../../models/platforms';
2122

2223
export interface DefaultAuthClientConfig {
2324
afterSignInUrl: string;
@@ -42,6 +43,12 @@ export interface DefaultAuthClientConfig {
4243
*/
4344
targetOrganizationId?: string;
4445
};
46+
/**
47+
* Optional platform where the application is running.
48+
* This helps the SDK to optimize its behavior based on the platform.
49+
* If not provided, the SDK will attempt to auto-detect the platform.
50+
*/
51+
platform?: keyof typeof Platform;
4552
prompt?: string;
4653
responseMode?: OAuthResponseMode;
4754
scopes?: string | string[] | undefined;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Copyright (c) 2026, 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+
/**
20+
* Constants related to OpenID Connect (OIDC) metadata and endpoints.
21+
* This object contains all the standard OIDC endpoints and storage keys
22+
* used throughout the application for authentication and authorization.
23+
*
24+
* @remarks
25+
* The constants are organized into two main sections:
26+
* 1. Endpoints - Contains all OIDC standard endpoint paths
27+
* 2. Storage - Contains keys used for storing OIDC-related data
28+
*
29+
* @example
30+
* ```typescript
31+
* // Using an endpoint
32+
* const wellKnownEndpoint = OIDCDiscoveryConstants.Endpoints.WELL_KNOWN;
33+
* ```
34+
*/
35+
const OIDCDiscoveryConstants: {
36+
readonly Endpoints: {
37+
readonly WELL_KNOWN: string;
38+
};
39+
} = {
40+
/**
41+
* Collection of standard OIDC endpoint paths used for authentication flows.
42+
* These endpoints are relative paths that should be appended to the base URL
43+
* of your identity provider.
44+
*/
45+
Endpoints: {
46+
/**
47+
* OpenID Connect discovery document endpoint.
48+
* Used to fetch provider metadata from the authorization server.
49+
*/
50+
WELL_KNOWN: '/.well-known/openid-configuration',
51+
},
52+
} as const;
53+
54+
export default OIDCDiscoveryConstants;

packages/javascript/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ export {
165165
ExtendedAuthorizeRequestUrlParams,
166166
} from './models/oauth-request';
167167
export {OIDCEndpoints} from './models/oidc-endpoints';
168+
export {OIDCDiscoveryApiResponse} from './models/oidc-discovery';
168169
export {Storage, TemporaryStore} from './models/store';
169170
export {User, UserProfile} from './models/user';
170171
export {SessionData} from './models/session';

packages/javascript/src/models/config.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,33 @@ export interface BaseConfig<T = unknown> extends WithPreferences {
123123
*/
124124
clientSecret?: string | undefined;
125125

126+
/**
127+
* OpenID Connect discovery configuration.
128+
* Controls how the SDK resolves endpoint URLs from the authorization server.
129+
* Each discovery mechanism is independently configurable.
130+
*
131+
* @example
132+
* // Use a custom well-known discovery document URL
133+
* discovery: { wellKnown: { endpoint: "https://custom.example.com/.well-known/openid-configuration" } }
134+
*
135+
* @example
136+
* // Disable well-known discovery entirely
137+
* discovery: { wellKnown: { enabled: false } }
138+
*/
139+
discovery?: {
140+
/**
141+
* Configuration for OpenID Connect Discovery via the well-known endpoint (RFC 8414).
142+
* The SDK fetches `{baseUrl}/oauth2/token/.well-known/openid-configuration` by default.
143+
*/
144+
wellKnown?: {
145+
/**
146+
* Whether to fetch and use the well-known discovery document to resolve endpoint URLs.
147+
* @default true
148+
*/
149+
enabled?: boolean;
150+
};
151+
};
152+
126153
/**
127154
* Optional instance ID for multi-auth context support.
128155
* Use this when you need multiple authentication contexts in the same application.
@@ -226,6 +253,60 @@ export interface BaseConfig<T = unknown> extends WithPreferences {
226253
* @see {@link https://openid.net/specs/openid-connect-session-management-1_0.html#IframeBasedSessionManagement}
227254
*/
228255
syncSession?: boolean;
256+
257+
/**
258+
* Optional overrides for the OIDC protocol endpoints.
259+
* By default, the SDK derives all endpoint URLs from the well-known discovery document
260+
* located at `{baseUrl}/oauth2/token/.well-known/openid-configuration`.
261+
* Use this when your authorization server exposes endpoints at non-standard paths,
262+
* or when a custom domain differs from `baseUrl`.
263+
*
264+
* Individual overrides take precedence over values resolved from the discovery document.
265+
*
266+
* @example
267+
* endpoints: {
268+
* wellKnown: "https://custom-domain.example.com/.well-known/openid-configuration",
269+
* authorization: "https://custom-domain.example.com/oauth2/authorize",
270+
* }
271+
*/
272+
endpoints?: {
273+
/**
274+
* The authorization endpoint URL.
275+
* If not provided, resolved from the well-known discovery document.
276+
*/
277+
authorization?: string;
278+
/**
279+
* The end-session (logout) endpoint URL.
280+
* If not provided, resolved from the well-known discovery document.
281+
*/
282+
endSession?: string;
283+
/**
284+
* The introspection endpoint URL.
285+
* If not provided, resolved from the well-known discovery document.
286+
*/
287+
introspection?: string;
288+
/**
289+
* The JSON Web Key Set (JWKS) endpoint URL used to fetch public keys for token verification.
290+
* If not provided, resolved from the well-known discovery document.
291+
*/
292+
jwks?: string;
293+
/**
294+
* The token endpoint URL.
295+
* If not provided, resolved from the well-known discovery document.
296+
*/
297+
token?: string;
298+
/**
299+
* The userinfo endpoint URL.
300+
* If not provided, resolved from the well-known discovery document.
301+
*/
302+
userInfo?: string;
303+
/**
304+
* The OpenID Connect discovery document URL.
305+
* Defaults to `{baseUrl}/oauth2/token/.well-known/openid-configuration`.
306+
*/
307+
wellKnown?: string;
308+
};
309+
229310
/**
230311
* Token validation configuration.
231312
* This allows you to configure how the SDK validates tokens received from the authorization server.

packages/react/src/AsgardeoReactClient.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import {
5151
EmbeddedSignInFlowResponseV2,
5252
executeEmbeddedSignUpFlowV2,
5353
EmbeddedSignInFlowStatusV2,
54+
OIDCDiscoveryApiResponse,
5455
} from '@asgardeo/browser';
5556
import AuthAPI from './__temp__/api';
5657
import getAllOrganizations from './api/getAllOrganizations';
@@ -124,17 +125,19 @@ class AsgardeoReactClient<T extends AsgardeoReactConfig = AsgardeoReactConfig> e
124125
resolvedOrganizationHandle = deriveOrganizationHandleFromBaseUrl(config?.baseUrl);
125126
}
126127

127-
return this.withLoading(async () =>
128-
this.asgardeo.init({...config, organizationHandle: resolvedOrganizationHandle} as any),
129-
);
128+
return this.withLoading(async () => {
129+
this.initializeConfig = {...config, organizationHandle: resolvedOrganizationHandle};
130+
131+
return this.asgardeo.init(this.initializeConfig as any);
132+
});
130133
}
131134

132135
override reInitialize(config: Partial<AsgardeoReactConfig>): Promise<boolean> {
133136
return this.withLoading(async () => {
134137
let isInitialized: boolean;
135138

136139
try {
137-
await this.asgardeo.reInitialize(config);
140+
await this.asgardeo.reInitialize(config as any);
138141

139142
isInitialized = true;
140143
} catch (error) {
@@ -522,6 +525,12 @@ class AsgardeoReactClient<T extends AsgardeoReactConfig = AsgardeoReactConfig> e
522525
return undefined;
523526
}
524527

528+
override async getDiscoveryResponse(): Promise<OIDCDiscoveryApiResponse | null> {
529+
const storageManager: any = await this.asgardeo.getStorageManager();
530+
531+
return storageManager.loadOpenIDProviderConfiguration();
532+
}
533+
525534
async request(requestConfig?: HttpRequestConfig): Promise<HttpResponse<any>> {
526535
return this.asgardeo.httpRequest(requestConfig);
527536
}

packages/react/src/contexts/Asgardeo/AsgardeoContext.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
HttpRequestConfig,
2222
HttpResponse,
2323
IdToken,
24+
OIDCDiscoveryApiResponse,
2425
Organization,
2526
SignInOptions,
2627
TokenExchangeRequestConfig,
@@ -38,6 +39,17 @@ export type AsgardeoContextProps = {
3839
applicationId: string | undefined;
3940
baseUrl: string | undefined;
4041
clientId: string | undefined;
42+
/**
43+
* OIDC discovery data.
44+
*/
45+
discovery: {
46+
/**
47+
* The response from the `.well-known/openid-configuration` endpoint.
48+
* Contains server capabilities, supported endpoints, and metadata.
49+
* `null` while loading or when discovery has not been fetched.
50+
*/
51+
wellKnown: OIDCDiscoveryApiResponse | null;
52+
};
4153
/**
4254
* Swaps the current access token with a new one based on the provided configuration (with a grant type).
4355
* @param config - Configuration for the token exchange request.
@@ -186,6 +198,9 @@ const AsgardeoContext: Context<AsgardeoContextProps | null> = createContext<null
186198
baseUrl: undefined,
187199
clearSession: () => {},
188200
clientId: undefined,
201+
discovery: {
202+
wellKnown: null,
203+
},
189204
exchangeToken: null,
190205
getAccessToken: null,
191206
getDecodedIdToken: null,

0 commit comments

Comments
 (0)