From 1521d4a30221d1d25626157337473366dce0abba Mon Sep 17 00:00:00 2001 From: Movin Silva Date: Wed, 17 Apr 2024 11:36:01 +0530 Subject: [PATCH 1/5] feat: :art: extract and expose parameters building logic out of getAuthorizationURL function can use the getAuthorizationURLParams() to build the authorize api call (usable for api based authentication) --- README.md | 43 ++++++++++++++ lib/src/client.ts | 49 +++++++++++++++ lib/src/constants/client-config.ts | 3 +- lib/src/core/authentication-core.ts | 92 ++++++++++++++++++----------- 4 files changed, 150 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 60aadf5e..8896aa96 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ If you are looking for an SDK to use in your application, then you can find the - [constructor](#constructor) - [initialize](#initialize) - [getDataLayer](#getDataLayer) + - [getAuthorizationURLParams](#getAuthorizationURLParams) - [getAuthorizationURL](#getAuthorizationURL) - [requestAccessToken](#requestAccessToken) - [getSignOutURL](#getSignOutURL) @@ -323,6 +324,48 @@ This method returns the `CryptoHelper` object used by the SDK to perform cryptog ```TypeScript const cryptoHelper = auth.getCryptoHelper(); ``` +--- + +### getAuthorizationURLParams + +```TypeScript +getAuthorizationURLParams(config?: GetAuthURLConfig, userID?: string): Promise> +``` + +#### Arguments + +1. config: [`GetAuthURLConfig`](#GetAuthURLConfig) (optional) + + An optional config object that has the necessary attributes to configure this method. The `forceInit` attribute can be set to `true` to trigger a request to the `.well-known` endpoint and obtain the OIDC endpoints. By default, a request to the `.well-known` endpoint will be sent only if a request to it had not been sent before. If you wish to force a request to the endpoint, you can use this attribute. + + The object can only contain key-value pairs that you wish to append as path parameters to the authorization URL. For example, to set the `fidp` parameter, you can insert `fidp` as a key and its value to this object. + +2. userID: `string` (optional) + + If you want to use the SDK to manage multiple user sessions, you can pass a unique ID here to generate an authorization URL specific to that user. This can be useful when this SDK is used in backend applications. + +#### Returns + +A Promise that resolves with the authorization URL Parameters. + +#### Description + +This method returns a Promise that resolves with the authorization URL Parameters. The user can use these parametres to build the authorization request. + +#### Example + +```TypeScript +const config = { + forceInit: true, + fidp: "fb" +} + +auth.getAuthorizationURLParams(config).then((params)=>{ + +}).catch((error)=>{ + console.error(error); +}); +``` --- diff --git a/lib/src/client.ts b/lib/src/client.ts index c7dbc581..f6480f2c 100644 --- a/lib/src/client.ts +++ b/lib/src/client.ts @@ -104,6 +104,7 @@ export class AsgardeoAuthClient { cryptoUtils: CryptoUtils, instanceID?: number ): Promise { + console.log("Newest Local PACKAGE!!"); const clientId: string = config.clientID; if (!AsgardeoAuthClient._instanceID) { @@ -169,6 +170,54 @@ export class AsgardeoAuthClient { return AsgardeoAuthClient._instanceID; } + /** + * This is an async method that returns a Promise that resolves with the authorization URL parameters. + * + * @param config - (Optional) A config object to force initialization and pass + * custom path parameters such as the fidp parameter. + * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user + * scenarios where each user should be uniquely identified. + * + * @returns - A promise that resolves with the authorization URL parameters. + * + * @example + * ``` + * auth.getAuthorizationURLParams().then((params)=>{ + * // console.log(params); + * }).catch((error)=>{ + * // console.error(error); + * }); + * ``` + * + * {@link https://github.com/asgardeo/asgardeo-auth-js-sdk/tree/master#getAuthorizationURLParams} + * + * @preserve + */ + public async getAuthorizationURLParams( + config?: GetAuthURLConfig, + userID?: string + ): Promise> { + const authRequestConfig: GetAuthURLConfig = { ...config }; + + delete authRequestConfig?.forceInit; + + if (await this._dataLayer.getTemporaryDataParameter(OP_CONFIG_INITIATED)) { + return this._authenticationCore.getAuthorizationURLParams( + authRequestConfig, + userID + ); + } + + return this._authenticationCore + .getOIDCProviderMetaData(config?.forceInit as boolean) + .then(() => { + return this._authenticationCore.getAuthorizationURLParams( + authRequestConfig, + userID + ); + }); + } + /** * This is an async method that returns a Promise that resolves with the authorization URL. * diff --git a/lib/src/constants/client-config.ts b/lib/src/constants/client-config.ts index e0edd810..3fc16d83 100644 --- a/lib/src/constants/client-config.ts +++ b/lib/src/constants/client-config.ts @@ -18,5 +18,6 @@ export enum ResponseMode { formPost = "form_post", - query = "query" + query = "query", + direct = "direct" } diff --git a/lib/src/core/authentication-core.ts b/lib/src/core/authentication-core.ts index 437810fd..3a5b5fd7 100644 --- a/lib/src/core/authentication-core.ts +++ b/lib/src/core/authentication-core.ts @@ -62,62 +62,60 @@ export class AuthenticationCore { this._oidcProviderMetaData = async () => await this._dataLayer.getOIDCProviderMetaData(); } - public async getAuthorizationURL(config?: AuthorizationURLParams, userID?: string): Promise { - const authorizeEndpoint: string = (await this._dataLayer.getOIDCProviderMetaDataParameter( - AUTHORIZATION_ENDPOINT as keyof OIDCProviderMetaData - )) as string; - + public async getAuthorizationURLParams( + config?: AuthorizationURLParams, + userID?: string + ): Promise> { const configData: StrictAuthClientConfig = await this._config(); - - if (!authorizeEndpoint || authorizeEndpoint.trim().length === 0) { - throw new AsgardeoAuthException( - "JS-AUTH_CORE-GAU-NF01", - "No authorization endpoint found.", - "No authorization endpoint was found in the OIDC provider meta data from the well-known endpoint " + - "or the authorization endpoint passed to the SDK is empty." - ); - } - - const authorizeRequest: URL = new URL(authorizeEndpoint); - - const authorizeRequestParams: Map = new Map(); - + + const authorizeRequestParams: Map = new Map< + string, + string + >(); + authorizeRequestParams.set("response_type", "code"); authorizeRequestParams.set("client_id", configData.clientID); - + let scope: string = OIDC_SCOPE; - + if (configData.scope && configData.scope.length > 0) { if (!configData.scope.includes(OIDC_SCOPE)) { configData.scope.push(OIDC_SCOPE); } scope = configData.scope.join(" "); } - + authorizeRequestParams.set("scope", scope); authorizeRequestParams.set("redirect_uri", configData.signInRedirectURL); - + if (configData.responseMode) { authorizeRequestParams.set("response_mode", configData.responseMode); } - - const pkceKey: string = await this._authenticationHelper.generatePKCEKey(userID); - + + const pkceKey: string = await this._authenticationHelper.generatePKCEKey( + userID + ); + if (configData.enablePKCE) { const codeVerifier: string = this._cryptoHelper?.getCodeVerifier(); - const codeChallenge: string = this._cryptoHelper?.getCodeChallenge(codeVerifier); - - await this._dataLayer.setTemporaryDataParameter(pkceKey, codeVerifier, userID); + const codeChallenge: string = + this._cryptoHelper?.getCodeChallenge(codeVerifier); + + await this._dataLayer.setTemporaryDataParameter( + pkceKey, + codeVerifier, + userID + ); authorizeRequestParams.set("code_challenge_method", "S256"); authorizeRequestParams.set("code_challenge", codeChallenge); } - + if (configData.prompt) { authorizeRequestParams.set("prompt", configData.prompt); } - + const customParams: AuthorizationURLParams | undefined = config; - + if (customParams) { for (const [ key, value ] of Object.entries(customParams)) { if (key != "" && value != "" && key !== STATE) { @@ -125,19 +123,41 @@ export class AuthenticationCore { } } } - + authorizeRequestParams.set( STATE, AuthenticationUtils.generateStateParamForRequestCorrelation( pkceKey, - customParams ? customParams[ STATE ]?.toString() : "" + customParams ? customParams[STATE]?.toString() : "" ) ); + + return authorizeRequestParams; + } - for (const [ key, value ] of authorizeRequestParams.entries()) { - authorizeRequest.searchParams.append(key, value); + public async getAuthorizationURL(config?: AuthorizationURLParams, userID?: string): Promise { + const authorizeEndpoint: string = (await this._dataLayer.getOIDCProviderMetaDataParameter( + AUTHORIZATION_ENDPOINT as keyof OIDCProviderMetaData + )) as string; + + if (!authorizeEndpoint || authorizeEndpoint.trim().length === 0) { + throw new AsgardeoAuthException( + "JS-AUTH_CORE-GAU-NF01", + "No authorization endpoint found.", + "No authorization endpoint was found in the OIDC provider meta data from the well-known endpoint " + + "or the authorization endpoint passed to the SDK is empty." + ); } + const authorizeRequest: URL = new URL(authorizeEndpoint); + + const authorizeRequestParams: Map = + await this.getAuthorizationURLParams(config, userID); + + for (const [ key, value ] of authorizeRequestParams.entries()) { + authorizeRequest.searchParams.append(key, value); + } + return authorizeRequest.toString(); } From 643ec7be42550b59da46a001d3a711bff37d3892 Mon Sep 17 00:00:00 2001 From: Movin Silva Date: Wed, 17 Apr 2024 11:49:34 +0530 Subject: [PATCH 2/5] docs: :memo: update the example for the getAuthorizationURLParams --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8896aa96..1dd0d166 100644 --- a/README.md +++ b/README.md @@ -361,7 +361,7 @@ const config = { } auth.getAuthorizationURLParams(config).then((params)=>{ - + console.log(params); }).catch((error)=>{ console.error(error); }); From 374d6bb1819bd12f9f6c2a28824914a13af448a4 Mon Sep 17 00:00:00 2001 From: Movin Silva <54905952+movinsilva@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:19:36 +0530 Subject: [PATCH 3/5] docs: Update README.md Co-authored-by: Pavindu Lakshan --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1dd0d166..fd455aaa 100644 --- a/README.md +++ b/README.md @@ -350,7 +350,7 @@ A Promise that resolves with the authorization URL Parameters. #### Description -This method returns a Promise that resolves with the authorization URL Parameters. The user can use these parametres to build the authorization request. +This method returns a Promise that resolves with the authorization URL Parameters, which then can be used to build the authorization request. #### Example From 6e266f8a77db85499c983c8ab64ed3bb802f925e Mon Sep 17 00:00:00 2001 From: Movin Silva Date: Wed, 17 Apr 2024 16:31:18 +0530 Subject: [PATCH 4/5] style: :art: remove whitespaces --- lib/src/client.ts | 1 - lib/src/core/authentication-core.ts | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/src/client.ts b/lib/src/client.ts index f6480f2c..a864160c 100644 --- a/lib/src/client.ts +++ b/lib/src/client.ts @@ -104,7 +104,6 @@ export class AsgardeoAuthClient { cryptoUtils: CryptoUtils, instanceID?: number ): Promise { - console.log("Newest Local PACKAGE!!"); const clientId: string = config.clientID; if (!AsgardeoAuthClient._instanceID) { diff --git a/lib/src/core/authentication-core.ts b/lib/src/core/authentication-core.ts index 3a5b5fd7..693fd88e 100644 --- a/lib/src/core/authentication-core.ts +++ b/lib/src/core/authentication-core.ts @@ -75,19 +75,19 @@ export class AuthenticationCore { authorizeRequestParams.set("response_type", "code"); authorizeRequestParams.set("client_id", configData.clientID); - + let scope: string = OIDC_SCOPE; - + if (configData.scope && configData.scope.length > 0) { if (!configData.scope.includes(OIDC_SCOPE)) { configData.scope.push(OIDC_SCOPE); } scope = configData.scope.join(" "); } - + authorizeRequestParams.set("scope", scope); authorizeRequestParams.set("redirect_uri", configData.signInRedirectURL); - + if (configData.responseMode) { authorizeRequestParams.set("response_mode", configData.responseMode); } @@ -109,13 +109,13 @@ export class AuthenticationCore { authorizeRequestParams.set("code_challenge_method", "S256"); authorizeRequestParams.set("code_challenge", codeChallenge); } - + if (configData.prompt) { authorizeRequestParams.set("prompt", configData.prompt); } - + const customParams: AuthorizationURLParams | undefined = config; - + if (customParams) { for (const [ key, value ] of Object.entries(customParams)) { if (key != "" && value != "" && key !== STATE) { @@ -123,7 +123,7 @@ export class AuthenticationCore { } } } - + authorizeRequestParams.set( STATE, AuthenticationUtils.generateStateParamForRequestCorrelation( @@ -149,14 +149,14 @@ export class AuthenticationCore { ); } - const authorizeRequest: URL = new URL(authorizeEndpoint); + const authorizeRequest: URL = new URL(authorizeEndpoint); - const authorizeRequestParams: Map = + const authorizeRequestParams: Map = await this.getAuthorizationURLParams(config, userID); - for (const [ key, value ] of authorizeRequestParams.entries()) { - authorizeRequest.searchParams.append(key, value); - } + for (const [ key, value ] of authorizeRequestParams.entries()) { + authorizeRequest.searchParams.append(key, value); + } return authorizeRequest.toString(); } From fe0a465f9f9c38596016e700f21bced3460a5578 Mon Sep 17 00:00:00 2001 From: Pavindu Lakshan Date: Thu, 18 Apr 2024 11:55:59 +0530 Subject: [PATCH 5/5] Update lib/src/client.ts --- lib/src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/client.ts b/lib/src/client.ts index a864160c..0cd384d0 100644 --- a/lib/src/client.ts +++ b/lib/src/client.ts @@ -173,7 +173,7 @@ export class AsgardeoAuthClient { * This is an async method that returns a Promise that resolves with the authorization URL parameters. * * @param config - (Optional) A config object to force initialization and pass - * custom path parameters such as the fidp parameter. + * custom path parameters such as the `fidp` parameter. * @param userID - (Optional) A unique ID of the user to be authenticated. This is useful in multi-user * scenarios where each user should be uniquely identified. *