From a8dee265acced95ce469a0426c6c193ccd607a19 Mon Sep 17 00:00:00 2001 From: lashini Date: Tue, 24 Feb 2026 14:15:23 +0530 Subject: [PATCH 1/5] Introduce new functions related to agent tokens --- .changeset/new-paws-cut.md | 7 + .../src/AsgardeoJavaScriptClient.ts | 277 ++++++++++++++---- packages/nextjs/src/AsgardeoNextClient.ts | 4 +- packages/react/src/AsgardeoReactClient.ts | 2 +- 4 files changed, 227 insertions(+), 63 deletions(-) create mode 100644 .changeset/new-paws-cut.md diff --git a/.changeset/new-paws-cut.md b/.changeset/new-paws-cut.md new file mode 100644 index 000000000..37daf7bf3 --- /dev/null +++ b/.changeset/new-paws-cut.md @@ -0,0 +1,7 @@ +--- +'@asgardeo/javascript': patch +'@asgardeo/nextjs': patch +'@asgardeo/react': patch +--- + +Introduce Agent token related functions diff --git a/packages/javascript/src/AsgardeoJavaScriptClient.ts b/packages/javascript/src/AsgardeoJavaScriptClient.ts index f6746bf67..3cd224e08 100644 --- a/packages/javascript/src/AsgardeoJavaScriptClient.ts +++ b/packages/javascript/src/AsgardeoJavaScriptClient.ts @@ -16,14 +16,34 @@ * under the License. */ +import { EmbeddedSignInFlowInitiateResponse } from "./models/embedded-signin-flow"; +import { AuthClientConfig } from './__legacy__/models/client-config'; +import { EmbeddedFlowExecuteRequestConfig } from "./models/embedded-flow"; +import { EmbeddedSignInFlowHandleResponse } from "./models/embedded-signin-flow"; +import { EmbeddedSignInFlowStatus } from "./models/embedded-signin-flow"; +import { Crypto } from "./models/crypto"; +import { AsgardeoAuthClient } from "./__legacy__/client"; +import StorageManager from "./StorageManager"; +import executeEmbeddedSignInFlow from "./api/executeEmbeddedSignInFlow"; import {AsgardeoClient} from './models/client'; import {Config, SignInOptions, SignOutOptions, SignUpOptions} from './models/config'; import {EmbeddedFlowExecuteRequestPayload, EmbeddedFlowExecuteResponse} from './models/embedded-flow'; -import {EmbeddedSignInFlowHandleRequestPayload} from './models/embedded-signin-flow'; import {AllOrganizationsApiResponse, Organization} from './models/organization'; import {Storage} from './models/store'; import {TokenExchangeRequestConfig, TokenResponse} from './models/token'; import {User, UserProfile} from './models/user'; +import initializeEmbeddedSignInFlow from './api/initializeEmbeddedSignInFlow'; + +interface AgentConfig { + agentID: string; + agentSecret: string; +} + +export interface AuthCodeResponse { + code: string; + state: string; + session_state: string; +} /** * Base class for implementing Asgardeo clients. @@ -31,65 +51,202 @@ import {User, UserProfile} from './models/user'; * * @typeParam T - Configuration type that extends Config. */ -abstract class AsgardeoJavaScriptClient implements AsgardeoClient { - abstract switchOrganization(organization: Organization, sessionId?: string): Promise; - - abstract initialize(config: T, storage?: Storage): Promise; - - abstract reInitialize(config: Partial): Promise; - - abstract getUser(options?: any): Promise; - - abstract getAllOrganizations(options?: any, sessionId?: string): Promise; - - abstract getMyOrganizations(options?: any, sessionId?: string): Promise; - - abstract getCurrentOrganization(sessionId?: string): Promise; - - abstract getUserProfile(options?: any): Promise; - - abstract isLoading(): boolean; - - abstract isSignedIn(): Promise; - - abstract updateUserProfile(payload: any, userId?: string): Promise; - - abstract getConfiguration(): T; - - abstract exchangeToken(config: TokenExchangeRequestConfig, sessionId?: string): Promise; - - abstract signIn( - options?: SignInOptions, - sessionId?: string, - onSignInSuccess?: (afterSignInUrl: string) => void, - ): Promise; - abstract signIn( - payload: EmbeddedSignInFlowHandleRequestPayload, - request: Request, - sessionId?: string, - onSignInSuccess?: (afterSignInUrl: string) => void, - ): Promise; - - abstract signInSilently(options?: SignInOptions): Promise; - - abstract signOut(options?: SignOutOptions, afterSignOut?: (afterSignOutUrl: string) => void): Promise; - abstract signOut( - options?: SignOutOptions, - sessionId?: string, - afterSignOut?: (afterSignOutUrl: string) => void, - ): Promise; - - abstract signUp(options?: SignUpOptions): Promise; - abstract signUp(payload: EmbeddedFlowExecuteRequestPayload): Promise; - abstract signUp(payload?: unknown): Promise | Promise; - - abstract getAccessToken(sessionId?: string): Promise; - - abstract clearSession(sessionId?: string): void; - - abstract setSession(sessionData: Record, sessionId?: string): Promise; - - abstract decodeJwtToken>(token: string): Promise; +class AsgardeoJavaScriptClient implements AsgardeoClient { + + private cacheStore: Storage; + private cryptoUtils: Crypto; + private auth: AsgardeoAuthClient; + private storageManager: StorageManager; + private baseURL: string; + void: void; + + constructor(config?: AuthClientConfig, cacheStore?: Storage, cryptoUtils?: Crypto) { + this.cacheStore = cacheStore; + this.cryptoUtils = cryptoUtils; + this.auth = new AsgardeoAuthClient(); + this.auth.initialize(config, this.cacheStore, this.cryptoUtils); + this.storageManager = this.auth.getStorageManager(); + + this.baseURL = config.baseUrl ?? ""; + } + + switchOrganization(organization: Organization, sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + initialize(config: T, storage?: Storage): Promise { + throw new Error("Method not implemented."); + } + + reInitialize(config: Partial): Promise { + throw new Error("Method not implemented."); + } + + getUser(options?: any): Promise { + throw new Error("Method not implemented."); + } + + getAllOrganizations(options?: any, sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + getMyOrganizations(options?: any, sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + getCurrentOrganization(sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + getUserProfile(options?: any): Promise { + throw new Error("Method not implemented."); + } + + isLoading(): boolean { + throw new Error("Method not implemented."); + } + + isSignedIn(): Promise { + throw new Error("Method not implemented."); + } + + updateUserProfile(payload: any, userId?: string): Promise { + throw new Error("Method not implemented."); + } + + getConfiguration(): T { + throw new Error("Method not implemented."); + } + + exchangeToken(config: TokenExchangeRequestConfig, sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + signInSilently(options?: SignInOptions): Promise { + throw new Error("Method not implemented."); + } + + getAccessToken(sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + clearSession(sessionId?: string): void { + throw new Error("Method not implemented."); + } + + setSession(sessionData: Record, sessionId?: string): Promise { + throw new Error("Method not implemented."); + } + + decodeJwtToken>(token: string): Promise { + throw new Error("Method not implemented."); + } + + signIn(options?: SignInOptions): Promise { + throw new Error("Method not implemented."); + } + + signOut(options?: SignOutOptions, sessionIdOrAfterSignOut?: string | ((afterSignOutUrl: string) => void), afterSignOut?: (afterSignOutUrl: string) => void): Promise { + throw new Error("Method not implemented."); + } + + signUp(options?: SignUpOptions): Promise; + + signUp(payload: EmbeddedFlowExecuteRequestPayload): Promise; + + signUp(optionsOrPayload?: SignUpOptions | EmbeddedFlowExecuteRequestPayload): Promise { + throw new Error("Method not implemented."); + } + + // Get Agent Token. (AI agent acting on its own) + public async getAgentToken(agentConfig: AgentConfig): Promise { + const customParam = { + response_mode: "direct", + }; + + const authorizeURL: URL = new URL(await this.auth.getSignInUrl(customParam)); + + const authorizeResponse: EmbeddedSignInFlowInitiateResponse = await initializeEmbeddedSignInFlow({ + url: `${authorizeURL.origin}${authorizeURL.pathname}`, + payload: Object.fromEntries(authorizeURL.searchParams.entries()), + }); + + const usernamePasswordAuthenticator = authorizeResponse.nextStep.authenticators.find( + (auth) => auth.authenticator === "Username & Password", + ); + + if (!usernamePasswordAuthenticator) { + console.error("Basic authenticator not found among authentication steps."); + return Promise.reject(new Error("Basic authenticator not found among authentication steps.")); + } + + const authnRequest: EmbeddedFlowExecuteRequestConfig = { + baseUrl: this.baseURL, + payload: { + flowId: authorizeResponse.flowId, + selectedAuthenticator: { + authenticatorId: usernamePasswordAuthenticator.authenticatorId, + params: { + username: agentConfig.agentID, + password: agentConfig.agentSecret, + }, + }, + }, + }; + + const authnResponse: EmbeddedSignInFlowHandleResponse = await executeEmbeddedSignInFlow(authnRequest); + + if (authnResponse.flowStatus != EmbeddedSignInFlowStatus.SuccessCompleted) { + console.error("Agent Authentication Failed."); + return Promise.reject(new Error("Agent Authentication Failed.")); + } + + const tokenResponse = await this.auth.requestAccessToken( + authnResponse.authData['code'], + authnResponse.authData['session_state'], + authnResponse.authData['state'], + ); + + return tokenResponse; + } + + // Build Authorize request for the OBO Flow + public async getOBOSignInURL(agentConfig: AgentConfig): Promise { + // The authorize request must include requested_actor parameter from the agent configs + const customParam = { + requested_actor: agentConfig.agentID, + }; + + // Build authorize URL using AsgardeoAuthClient + const authURL: string | undefined = await this.auth.getSignInUrl(customParam); + + if (authURL) { + return Promise.resolve(authURL.toString()); + } + return Promise.reject(new Error("Could not build Authorize URL")); + } + + // Get OBO Token. (AI agent acting on behalf of a user) + public async getOBOToken(agentConfig: AgentConfig, authCodeResponse: AuthCodeResponse): Promise { + // Get Agent Token + const agentToken = await this.getAgentToken(agentConfig); + + // Pass Agent Token when requesting access token + const tokenRequestConfig = { + params: { + actor_token: agentToken.accessToken, + }, + }; + + // Return OBO Token + return await this.auth.requestAccessToken( + authCodeResponse.code, + authCodeResponse.session_state, + authCodeResponse.state, + undefined, + tokenRequestConfig + ); + } } export default AsgardeoJavaScriptClient; diff --git a/packages/nextjs/src/AsgardeoNextClient.ts b/packages/nextjs/src/AsgardeoNextClient.ts index 537871777..1f7e16277 100644 --- a/packages/nextjs/src/AsgardeoNextClient.ts +++ b/packages/nextjs/src/AsgardeoNextClient.ts @@ -412,7 +412,7 @@ class AsgardeoNextClient exte * otherwise falls back to legacy client method. */ // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars - async getAccessToken(_sessionId?: string): Promise { + override async getAccessToken(_sessionId?: string): Promise { const {default: getAccessToken} = await import('./server/actions/getAccessToken'); const token: string | undefined = await getAccessToken(); @@ -573,7 +573,7 @@ class AsgardeoNextClient exte } // eslint-disable-next-line class-methods-use-this - public async clearSession(): Promise { + public override async clearSession(): Promise { throw new AsgardeoRuntimeError( 'Not implemented', 'AsgardeoNextClient-clearSession-NotImplementedError-001', diff --git a/packages/react/src/AsgardeoReactClient.ts b/packages/react/src/AsgardeoReactClient.ts index eb3d2884d..365ad2095 100644 --- a/packages/react/src/AsgardeoReactClient.ts +++ b/packages/react/src/AsgardeoReactClient.ts @@ -179,7 +179,7 @@ class AsgardeoReactClient e return this.withLoading(async () => this.asgardeo.getIdToken()); } - async getUserProfile(options?: any): Promise { + override async getUserProfile(options?: any): Promise { return this.withLoading(async () => { try { let baseUrl: string = options?.baseUrl; From e744cc88bc6238d2d8f5a78bd96368e7e12467af Mon Sep 17 00:00:00 2001 From: lashini Date: Tue, 24 Feb 2026 14:17:56 +0530 Subject: [PATCH 2/5] formatting fixes --- .../src/AsgardeoJavaScriptClient.ts | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/packages/javascript/src/AsgardeoJavaScriptClient.ts b/packages/javascript/src/AsgardeoJavaScriptClient.ts index 3cd224e08..74f0e911b 100644 --- a/packages/javascript/src/AsgardeoJavaScriptClient.ts +++ b/packages/javascript/src/AsgardeoJavaScriptClient.ts @@ -159,94 +159,94 @@ class AsgardeoJavaScriptClient implements AsgardeoClient { } // Get Agent Token. (AI agent acting on its own) - public async getAgentToken(agentConfig: AgentConfig): Promise { - const customParam = { - response_mode: "direct", - }; - - const authorizeURL: URL = new URL(await this.auth.getSignInUrl(customParam)); - - const authorizeResponse: EmbeddedSignInFlowInitiateResponse = await initializeEmbeddedSignInFlow({ - url: `${authorizeURL.origin}${authorizeURL.pathname}`, - payload: Object.fromEntries(authorizeURL.searchParams.entries()), - }); - - const usernamePasswordAuthenticator = authorizeResponse.nextStep.authenticators.find( - (auth) => auth.authenticator === "Username & Password", - ); - - if (!usernamePasswordAuthenticator) { - console.error("Basic authenticator not found among authentication steps."); - return Promise.reject(new Error("Basic authenticator not found among authentication steps.")); - } - - const authnRequest: EmbeddedFlowExecuteRequestConfig = { - baseUrl: this.baseURL, - payload: { - flowId: authorizeResponse.flowId, - selectedAuthenticator: { - authenticatorId: usernamePasswordAuthenticator.authenticatorId, - params: { - username: agentConfig.agentID, - password: agentConfig.agentSecret, - }, - }, - }, - }; + public async getAgentToken(agentConfig: AgentConfig): Promise { + const customParam = { + response_mode: "direct", + }; - const authnResponse: EmbeddedSignInFlowHandleResponse = await executeEmbeddedSignInFlow(authnRequest); + const authorizeURL: URL = new URL(await this.auth.getSignInUrl(customParam)); - if (authnResponse.flowStatus != EmbeddedSignInFlowStatus.SuccessCompleted) { - console.error("Agent Authentication Failed."); - return Promise.reject(new Error("Agent Authentication Failed.")); - } + const authorizeResponse: EmbeddedSignInFlowInitiateResponse = await initializeEmbeddedSignInFlow({ + url: `${authorizeURL.origin}${authorizeURL.pathname}`, + payload: Object.fromEntries(authorizeURL.searchParams.entries()), + }); - const tokenResponse = await this.auth.requestAccessToken( - authnResponse.authData['code'], - authnResponse.authData['session_state'], - authnResponse.authData['state'], - ); + const usernamePasswordAuthenticator = authorizeResponse.nextStep.authenticators.find( + (auth) => auth.authenticator === "Username & Password", + ); - return tokenResponse; + if (!usernamePasswordAuthenticator) { + console.error("Basic authenticator not found among authentication steps."); + return Promise.reject(new Error("Basic authenticator not found among authentication steps.")); } - // Build Authorize request for the OBO Flow - public async getOBOSignInURL(agentConfig: AgentConfig): Promise { - // The authorize request must include requested_actor parameter from the agent configs - const customParam = { - requested_actor: agentConfig.agentID, - }; + const authnRequest: EmbeddedFlowExecuteRequestConfig = { + baseUrl: this.baseURL, + payload: { + flowId: authorizeResponse.flowId, + selectedAuthenticator: { + authenticatorId: usernamePasswordAuthenticator.authenticatorId, + params: { + username: agentConfig.agentID, + password: agentConfig.agentSecret, + }, + }, + }, + }; - // Build authorize URL using AsgardeoAuthClient - const authURL: string | undefined = await this.auth.getSignInUrl(customParam); + const authnResponse: EmbeddedSignInFlowHandleResponse = await executeEmbeddedSignInFlow(authnRequest); - if (authURL) { - return Promise.resolve(authURL.toString()); - } - return Promise.reject(new Error("Could not build Authorize URL")); + if (authnResponse.flowStatus != EmbeddedSignInFlowStatus.SuccessCompleted) { + console.error("Agent Authentication Failed."); + return Promise.reject(new Error("Agent Authentication Failed.")); } - // Get OBO Token. (AI agent acting on behalf of a user) - public async getOBOToken(agentConfig: AgentConfig, authCodeResponse: AuthCodeResponse): Promise { - // Get Agent Token - const agentToken = await this.getAgentToken(agentConfig); + const tokenResponse = await this.auth.requestAccessToken( + authnResponse.authData['code'], + authnResponse.authData['session_state'], + authnResponse.authData['state'], + ); - // Pass Agent Token when requesting access token - const tokenRequestConfig = { - params: { - actor_token: agentToken.accessToken, - }, - }; - - // Return OBO Token - return await this.auth.requestAccessToken( - authCodeResponse.code, - authCodeResponse.session_state, - authCodeResponse.state, - undefined, - tokenRequestConfig - ); + return tokenResponse; + } + + // Build Authorize request for the OBO Flow + public async getOBOSignInURL(agentConfig: AgentConfig): Promise { + // The authorize request must include requested_actor parameter from the agent configs + const customParam = { + requested_actor: agentConfig.agentID, + }; + + // Build authorize URL using AsgardeoAuthClient + const authURL: string | undefined = await this.auth.getSignInUrl(customParam); + + if (authURL) { + return Promise.resolve(authURL.toString()); } + return Promise.reject(new Error("Could not build Authorize URL")); + } + + // Get OBO Token. (AI agent acting on behalf of a user) + public async getOBOToken(agentConfig: AgentConfig, authCodeResponse: AuthCodeResponse): Promise { + // Get Agent Token + const agentToken = await this.getAgentToken(agentConfig); + + // Pass Agent Token when requesting access token + const tokenRequestConfig = { + params: { + actor_token: agentToken.accessToken, + }, + }; + + // Return OBO Token + return await this.auth.requestAccessToken( + authCodeResponse.code, + authCodeResponse.session_state, + authCodeResponse.state, + undefined, + tokenRequestConfig + ); + } } export default AsgardeoJavaScriptClient; From dd1d91fb15522679a6733ae53575237b84bd6b9c Mon Sep 17 00:00:00 2001 From: lashini Date: Tue, 24 Feb 2026 14:53:05 +0530 Subject: [PATCH 3/5] formatting fixes --- .../javascript/src/AsgardeoJavaScriptClient.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/javascript/src/AsgardeoJavaScriptClient.ts b/packages/javascript/src/AsgardeoJavaScriptClient.ts index 74f0e911b..a7118616c 100644 --- a/packages/javascript/src/AsgardeoJavaScriptClient.ts +++ b/packages/javascript/src/AsgardeoJavaScriptClient.ts @@ -16,13 +16,13 @@ * under the License. */ -import { EmbeddedSignInFlowInitiateResponse } from "./models/embedded-signin-flow"; -import { AuthClientConfig } from './__legacy__/models/client-config'; -import { EmbeddedFlowExecuteRequestConfig } from "./models/embedded-flow"; -import { EmbeddedSignInFlowHandleResponse } from "./models/embedded-signin-flow"; -import { EmbeddedSignInFlowStatus } from "./models/embedded-signin-flow"; -import { Crypto } from "./models/crypto"; -import { AsgardeoAuthClient } from "./__legacy__/client"; +import {EmbeddedSignInFlowInitiateResponse} from "./models/embedded-signin-flow"; +import {AuthClientConfig} from './__legacy__/models/client-config'; +import {EmbeddedFlowExecuteRequestConfig} from "./models/embedded-flow"; +import {EmbeddedSignInFlowHandleResponse} from "./models/embedded-signin-flow"; +import {EmbeddedSignInFlowStatus} from "./models/embedded-signin-flow"; +import {Crypto} from "./models/crypto"; +import {AsgardeoAuthClient} from "./__legacy__/client"; import StorageManager from "./StorageManager"; import executeEmbeddedSignInFlow from "./api/executeEmbeddedSignInFlow"; import {AsgardeoClient} from './models/client'; From 1ec8d397c6956880dc80c9daeeff99b20c66401f Mon Sep 17 00:00:00 2001 From: lashini Date: Tue, 24 Feb 2026 16:34:36 +0530 Subject: [PATCH 4/5] Add DefaultCacheStore and DefaultCrypto Services --- packages/javascript/package.json | 4 +- .../src/AsgardeoJavaScriptClient.ts | 6 +- packages/javascript/src/DefaultCacheStore.ts | 63 ++++++++++++ packages/javascript/src/DefaultCrypto.ts | 99 +++++++++++++++++++ packages/javascript/src/IsomorphicCrypto.ts | 5 +- packages/javascript/src/__legacy__/client.ts | 2 +- 6 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 packages/javascript/src/DefaultCacheStore.ts create mode 100644 packages/javascript/src/DefaultCrypto.ts diff --git a/packages/javascript/package.json b/packages/javascript/package.json index 62adfbf74..0982a6b36 100644 --- a/packages/javascript/package.json +++ b/packages/javascript/package.json @@ -54,7 +54,9 @@ }, "dependencies": { "@asgardeo/i18n": "workspace:*", - "tslib": "2.8.1" + "tslib": "2.8.1", + "base64url": "^3.0.1", + "jose": "^5.2.0" }, "publishConfig": { "access": "public" diff --git a/packages/javascript/src/AsgardeoJavaScriptClient.ts b/packages/javascript/src/AsgardeoJavaScriptClient.ts index a7118616c..d87ea55e8 100644 --- a/packages/javascript/src/AsgardeoJavaScriptClient.ts +++ b/packages/javascript/src/AsgardeoJavaScriptClient.ts @@ -33,6 +33,8 @@ import {Storage} from './models/store'; import {TokenExchangeRequestConfig, TokenResponse} from './models/token'; import {User, UserProfile} from './models/user'; import initializeEmbeddedSignInFlow from './api/initializeEmbeddedSignInFlow'; +import {DefaultCacheStore} from './DefaultCacheStore'; +import {DefaultCrypto} from './DefaultCrypto'; interface AgentConfig { agentID: string; @@ -61,8 +63,8 @@ class AsgardeoJavaScriptClient implements AsgardeoClient { void: void; constructor(config?: AuthClientConfig, cacheStore?: Storage, cryptoUtils?: Crypto) { - this.cacheStore = cacheStore; - this.cryptoUtils = cryptoUtils; + this.cacheStore = cacheStore ?? new DefaultCacheStore(); + this.cryptoUtils = cryptoUtils ?? new DefaultCrypto(); this.auth = new AsgardeoAuthClient(); this.auth.initialize(config, this.cacheStore, this.cryptoUtils); this.storageManager = this.auth.getStorageManager(); diff --git a/packages/javascript/src/DefaultCacheStore.ts b/packages/javascript/src/DefaultCacheStore.ts new file mode 100644 index 000000000..fe71ab9c3 --- /dev/null +++ b/packages/javascript/src/DefaultCacheStore.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export class DefaultCacheStore implements Storage { + + private cache: Map; + + constructor() { + this.cache = new Map(); + } + + public get length(): number { + return this.cache.size; + } + + public getItem(key: string): string | null { + return this.cache.get(key) ?? null; + } + + public setItem(key: string, value: string): void { + this.cache.set(key, value); + } + + public removeItem(key: string): void { + this.cache.delete(key); + } + + public clear(): void { + this.cache.clear(); + } + + public key(index: number): string | null { + const keys = Array.from(this.cache.keys()); + return keys[index] ?? null; + } + + public async setData(key: string, value: string): Promise { + this.cache.set(key, value); + } + + public async getData(key: string): Promise { + return this.cache.get(key) ?? "{}"; + } + + public async removeData(key: string): Promise { + this.cache.delete(key); + } +} diff --git a/packages/javascript/src/DefaultCrypto.ts b/packages/javascript/src/DefaultCrypto.ts new file mode 100644 index 000000000..63d005b75 --- /dev/null +++ b/packages/javascript/src/DefaultCrypto.ts @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as jose from "jose"; +import { JWKInterface } from "./models/crypto"; + +interface CryptoInterface { + base64URLEncode(value: T): string; + base64URLDecode(value: string): string; + hashSha256(data: string): Promise; // Changed to Promise to match implementation + generateRandomBytes(length: number): Uint8Array; + verifyJwt( + idToken: string, + jwk: Partial, + algorithms: string[], + clientId: string, + issuer: string, + subject: string, + clockTolerance?: number, + ): Promise; +} + +export class DefaultCrypto implements CryptoInterface { + + constructor() {} + + /** + * Cross-platform Base64URL encoding using 'jose' utilities + */ + public base64URLEncode(value: Uint8Array | string): string { + const uint8Array = typeof value === "string" + ? new TextEncoder().encode(value) + : value; + + return jose.base64url.encode(uint8Array); + } + + /** + * Cross-platform Base64URL decoding + */ + public base64URLDecode(value: string): string { + const decodedArray = jose.base64url.decode(value); + return new TextDecoder().decode(decodedArray); + } + + public async hashSha256(data: string): Promise { + const encoder = new TextEncoder(); + const dataBuffer = encoder.encode(data); + + // Using native web crypto (available in modern Node and Browsers) + const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer); + return new Uint8Array(hashBuffer); + } + + public generateRandomBytes(length: number): Uint8Array { + // globalThis.crypto works in Browsers and Node.js 19+ + const array = new Uint8Array(length); + crypto.getRandomValues(array); + return array; + } + + public async verifyJwt( + idToken: string, + jwk: Partial, + algorithms: string[], + clientId: string, + issuer: string, + subject: string, + clockTolerance?: number, + ): Promise { + + const key = await jose.importJWK(jwk as any); + + await jose.jwtVerify(idToken, key, { + algorithms, + audience: clientId, + issuer, + subject, + clockTolerance, + }); + + return true; + } +} diff --git a/packages/javascript/src/IsomorphicCrypto.ts b/packages/javascript/src/IsomorphicCrypto.ts index 2e68015c1..85c744124 100644 --- a/packages/javascript/src/IsomorphicCrypto.ts +++ b/packages/javascript/src/IsomorphicCrypto.ts @@ -43,8 +43,9 @@ export class IsomorphicCrypto { * * @returns - code challenge. */ - public getCodeChallenge(verifier: string): string { - return this.cryptoUtils.base64URLEncode(this.cryptoUtils.hashSha256(verifier)); + public async getCodeChallenge(verifier: string): Promise { + const hashed = await this.cryptoUtils.hashSha256(verifier); + return this.cryptoUtils.base64URLEncode(hashed); } /** diff --git a/packages/javascript/src/__legacy__/client.ts b/packages/javascript/src/__legacy__/client.ts index 043829737..4ae0dd79c 100644 --- a/packages/javascript/src/__legacy__/client.ts +++ b/packages/javascript/src/__legacy__/client.ts @@ -242,7 +242,7 @@ export class AsgardeoAuthClient { if (configData.enablePKCE) { codeVerifier = this.cryptoHelper?.getCodeVerifier(); - codeChallenge = this.cryptoHelper?.getCodeChallenge(codeVerifier); + codeChallenge = await this.cryptoHelper?.getCodeChallenge(codeVerifier); await this.storageManager.setTemporaryDataParameter(pkceKey, codeVerifier, userId); } From b8d070f5d2cbd5b4713bd24607264e4476f677c2 Mon Sep 17 00:00:00 2001 From: lashini Date: Wed, 25 Feb 2026 09:48:58 +0530 Subject: [PATCH 5/5] address review comments --- packages/javascript/package.json | 1 - .../src/AsgardeoJavaScriptClient.ts | 210 +++++++++--------- packages/javascript/src/DefaultCacheStore.ts | 65 +++--- packages/javascript/src/DefaultCrypto.ts | 120 ++++------ packages/javascript/src/IsomorphicCrypto.ts | 2 +- packages/javascript/src/index.ts | 2 + packages/javascript/src/models/agent.ts | 46 ++++ .../src/models/auth-code-response.ts | 35 +++ packages/javascript/src/models/crypto.ts | 2 +- pnpm-lock.yaml | 55 +++-- 10 files changed, 306 insertions(+), 232 deletions(-) create mode 100644 packages/javascript/src/models/agent.ts create mode 100644 packages/javascript/src/models/auth-code-response.ts diff --git a/packages/javascript/package.json b/packages/javascript/package.json index 0982a6b36..35fa5ca95 100644 --- a/packages/javascript/package.json +++ b/packages/javascript/package.json @@ -55,7 +55,6 @@ "dependencies": { "@asgardeo/i18n": "workspace:*", "tslib": "2.8.1", - "base64url": "^3.0.1", "jose": "^5.2.0" }, "publishConfig": { diff --git a/packages/javascript/src/AsgardeoJavaScriptClient.ts b/packages/javascript/src/AsgardeoJavaScriptClient.ts index d87ea55e8..d1038ac81 100644 --- a/packages/javascript/src/AsgardeoJavaScriptClient.ts +++ b/packages/javascript/src/AsgardeoJavaScriptClient.ts @@ -16,170 +16,175 @@ * under the License. */ -import {EmbeddedSignInFlowInitiateResponse} from "./models/embedded-signin-flow"; +import {AsgardeoAuthClient} from './__legacy__/client'; import {AuthClientConfig} from './__legacy__/models/client-config'; -import {EmbeddedFlowExecuteRequestConfig} from "./models/embedded-flow"; -import {EmbeddedSignInFlowHandleResponse} from "./models/embedded-signin-flow"; -import {EmbeddedSignInFlowStatus} from "./models/embedded-signin-flow"; -import {Crypto} from "./models/crypto"; -import {AsgardeoAuthClient} from "./__legacy__/client"; -import StorageManager from "./StorageManager"; -import executeEmbeddedSignInFlow from "./api/executeEmbeddedSignInFlow"; +import executeEmbeddedSignInFlow from './api/executeEmbeddedSignInFlow'; +import initializeEmbeddedSignInFlow from './api/initializeEmbeddedSignInFlow'; +import {DefaultCacheStore} from './DefaultCacheStore'; +import {DefaultCrypto} from './DefaultCrypto'; +import {AgentConfig} from './models/agent'; +import {AuthCodeResponse} from './models/auth-code-response'; import {AsgardeoClient} from './models/client'; import {Config, SignInOptions, SignOutOptions, SignUpOptions} from './models/config'; -import {EmbeddedFlowExecuteRequestPayload, EmbeddedFlowExecuteResponse} from './models/embedded-flow'; +import {Crypto} from './models/crypto'; +import { + EmbeddedFlowExecuteRequestConfig, + EmbeddedFlowExecuteRequestPayload, + EmbeddedFlowExecuteResponse, +} from './models/embedded-flow'; +import { + EmbeddedSignInFlowAuthenticator, + EmbeddedSignInFlowHandleResponse, + EmbeddedSignInFlowInitiateResponse, + EmbeddedSignInFlowStatus, +} from './models/embedded-signin-flow'; import {AllOrganizationsApiResponse, Organization} from './models/organization'; import {Storage} from './models/store'; import {TokenExchangeRequestConfig, TokenResponse} from './models/token'; import {User, UserProfile} from './models/user'; -import initializeEmbeddedSignInFlow from './api/initializeEmbeddedSignInFlow'; -import {DefaultCacheStore} from './DefaultCacheStore'; -import {DefaultCrypto} from './DefaultCrypto'; - -interface AgentConfig { - agentID: string; - agentSecret: string; -} +import StorageManager from './StorageManager'; -export interface AuthCodeResponse { - code: string; - state: string; - session_state: string; -} - -/** - * Base class for implementing Asgardeo clients. - * This class provides the core functionality for managing user authentication and sessions. - * - * @typeParam T - Configuration type that extends Config. - */ class AsgardeoJavaScriptClient implements AsgardeoClient { - private cacheStore: Storage; + private cryptoUtils: Crypto; + private auth: AsgardeoAuthClient; + private storageManager: StorageManager; + private baseURL: string; - void: void; - + constructor(config?: AuthClientConfig, cacheStore?: Storage, cryptoUtils?: Crypto) { this.cacheStore = cacheStore ?? new DefaultCacheStore(); - this.cryptoUtils = cryptoUtils ?? new DefaultCrypto(); + this.cryptoUtils = cryptoUtils ?? new DefaultCrypto(); this.auth = new AsgardeoAuthClient(); - this.auth.initialize(config, this.cacheStore, this.cryptoUtils); - this.storageManager = this.auth.getStorageManager(); - this.baseURL = config.baseUrl ?? ""; + if (config) { + this.auth.initialize(config, this.cacheStore, this.cryptoUtils); + this.storageManager = this.auth.getStorageManager(); + } + + this.baseURL = config?.baseUrl ?? ''; } - switchOrganization(organization: Organization, sessionId?: string): Promise { - throw new Error("Method not implemented."); + /* eslint-disable class-methods-use-this, @typescript-eslint/no-unused-vars */ + switchOrganization(_organization: Organization, _sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - initialize(config: T, storage?: Storage): Promise { - throw new Error("Method not implemented."); + initialize(_config: T, _storage?: Storage): Promise { + throw new Error('Method not implemented.'); } - reInitialize(config: Partial): Promise { - throw new Error("Method not implemented."); + reInitialize(_config: Partial): Promise { + throw new Error('Method not implemented.'); } - getUser(options?: any): Promise { - throw new Error("Method not implemented."); + getUser(_options?: any): Promise { + throw new Error('Method not implemented.'); } - getAllOrganizations(options?: any, sessionId?: string): Promise { - throw new Error("Method not implemented."); + getAllOrganizations(_options?: any, _sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - getMyOrganizations(options?: any, sessionId?: string): Promise { - throw new Error("Method not implemented."); + getMyOrganizations(_options?: any, _sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - getCurrentOrganization(sessionId?: string): Promise { - throw new Error("Method not implemented."); + getCurrentOrganization(_sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - getUserProfile(options?: any): Promise { - throw new Error("Method not implemented."); + getUserProfile(_options?: any): Promise { + throw new Error('Method not implemented.'); } isLoading(): boolean { - throw new Error("Method not implemented."); + throw new Error('Method not implemented.'); } isSignedIn(): Promise { - throw new Error("Method not implemented."); + throw new Error('Method not implemented.'); } - updateUserProfile(payload: any, userId?: string): Promise { - throw new Error("Method not implemented."); + updateUserProfile(_payload: any, _userId?: string): Promise { + throw new Error('Method not implemented.'); } getConfiguration(): T { - throw new Error("Method not implemented."); + throw new Error('Method not implemented.'); } - exchangeToken(config: TokenExchangeRequestConfig, sessionId?: string): Promise { - throw new Error("Method not implemented."); + exchangeToken(_config: TokenExchangeRequestConfig, _sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - signInSilently(options?: SignInOptions): Promise { - throw new Error("Method not implemented."); + signInSilently(_options?: SignInOptions): Promise { + throw new Error('Method not implemented.'); } - getAccessToken(sessionId?: string): Promise { - throw new Error("Method not implemented."); + getAccessToken(_sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - clearSession(sessionId?: string): void { - throw new Error("Method not implemented."); + clearSession(_sessionId?: string): void { + throw new Error('Method not implemented.'); } - setSession(sessionData: Record, sessionId?: string): Promise { - throw new Error("Method not implemented."); + setSession(_sessionData: Record, _sessionId?: string): Promise { + throw new Error('Method not implemented.'); } - decodeJwtToken>(token: string): Promise { - throw new Error("Method not implemented."); + decodeJwtToken>(_token: string): Promise { + throw new Error('Method not implemented.'); } - signIn(options?: SignInOptions): Promise { - throw new Error("Method not implemented."); + signIn(_options?: SignInOptions): Promise { + throw new Error('Method not implemented.'); } - signOut(options?: SignOutOptions, sessionIdOrAfterSignOut?: string | ((afterSignOutUrl: string) => void), afterSignOut?: (afterSignOutUrl: string) => void): Promise { - throw new Error("Method not implemented."); + signOut( + _options?: SignOutOptions, + _sessionIdOrAfterSignOut?: string | ((afterSignOutUrl: string) => void), + _afterSignOut?: (afterSignOutUrl: string) => void, + ): Promise { + throw new Error('Method not implemented.'); } signUp(options?: SignUpOptions): Promise; signUp(payload: EmbeddedFlowExecuteRequestPayload): Promise; - signUp(optionsOrPayload?: SignUpOptions | EmbeddedFlowExecuteRequestPayload): Promise { - throw new Error("Method not implemented."); + signUp( + _optionsOrPayload?: SignUpOptions | EmbeddedFlowExecuteRequestPayload, + ): Promise { + throw new Error('Method not implemented.'); } + /* eslint-enable class-methods-use-this, @typescript-eslint/no-unused-vars */ - // Get Agent Token. (AI agent acting on its own) public async getAgentToken(agentConfig: AgentConfig): Promise { - const customParam = { - response_mode: "direct", + const customParam: Record = { + response_mode: 'direct', }; const authorizeURL: URL = new URL(await this.auth.getSignInUrl(customParam)); const authorizeResponse: EmbeddedSignInFlowInitiateResponse = await initializeEmbeddedSignInFlow({ - url: `${authorizeURL.origin}${authorizeURL.pathname}`, payload: Object.fromEntries(authorizeURL.searchParams.entries()), + url: `${authorizeURL.origin}${authorizeURL.pathname}`, }); - const usernamePasswordAuthenticator = authorizeResponse.nextStep.authenticators.find( - (auth) => auth.authenticator === "Username & Password", - ); + const authenticatorName: string = agentConfig.authenticatorName ?? AgentConfig.DEFAULT_AUTHENTICATOR_NAME; - if (!usernamePasswordAuthenticator) { - console.error("Basic authenticator not found among authentication steps."); - return Promise.reject(new Error("Basic authenticator not found among authentication steps.")); + const targetAuthenticator: EmbeddedSignInFlowAuthenticator | undefined = + authorizeResponse.nextStep.authenticators.find( + (auth: EmbeddedSignInFlowAuthenticator) => auth.authenticator === authenticatorName, + ); + + if (!targetAuthenticator) { + throw new Error(`Authenticator '${authenticatorName}' not found among authentication steps.`); } const authnRequest: EmbeddedFlowExecuteRequestConfig = { @@ -187,10 +192,10 @@ class AsgardeoJavaScriptClient implements AsgardeoClient { payload: { flowId: authorizeResponse.flowId, selectedAuthenticator: { - authenticatorId: usernamePasswordAuthenticator.authenticatorId, + authenticatorId: targetAuthenticator.authenticatorId, params: { - username: agentConfig.agentID, password: agentConfig.agentSecret, + username: agentConfig.agentID, }, }, }, @@ -198,55 +203,46 @@ class AsgardeoJavaScriptClient implements AsgardeoClient { const authnResponse: EmbeddedSignInFlowHandleResponse = await executeEmbeddedSignInFlow(authnRequest); - if (authnResponse.flowStatus != EmbeddedSignInFlowStatus.SuccessCompleted) { - console.error("Agent Authentication Failed."); - return Promise.reject(new Error("Agent Authentication Failed.")); + if (authnResponse.flowStatus !== EmbeddedSignInFlowStatus.SuccessCompleted) { + throw new Error('Agent authentication failed.'); } - const tokenResponse = await this.auth.requestAccessToken( + return this.auth.requestAccessToken( authnResponse.authData['code'], authnResponse.authData['session_state'], authnResponse.authData['state'], ); - - return tokenResponse; } - // Build Authorize request for the OBO Flow public async getOBOSignInURL(agentConfig: AgentConfig): Promise { - // The authorize request must include requested_actor parameter from the agent configs - const customParam = { + const customParam: Record = { requested_actor: agentConfig.agentID, }; - // Build authorize URL using AsgardeoAuthClient const authURL: string | undefined = await this.auth.getSignInUrl(customParam); if (authURL) { - return Promise.resolve(authURL.toString()); + return authURL.toString(); } - return Promise.reject(new Error("Could not build Authorize URL")); + + throw new Error('Could not build Authorize URL'); } - // Get OBO Token. (AI agent acting on behalf of a user) public async getOBOToken(agentConfig: AgentConfig, authCodeResponse: AuthCodeResponse): Promise { - // Get Agent Token - const agentToken = await this.getAgentToken(agentConfig); + const agentToken: TokenResponse = await this.getAgentToken(agentConfig); - // Pass Agent Token when requesting access token - const tokenRequestConfig = { + const tokenRequestConfig: {params: {actor_token: string}} = { params: { actor_token: agentToken.accessToken, }, }; - // Return OBO Token - return await this.auth.requestAccessToken( + return this.auth.requestAccessToken( authCodeResponse.code, authCodeResponse.session_state, authCodeResponse.state, undefined, - tokenRequestConfig + tokenRequestConfig, ); } } diff --git a/packages/javascript/src/DefaultCacheStore.ts b/packages/javascript/src/DefaultCacheStore.ts index fe71ab9c3..f749658c1 100644 --- a/packages/javascript/src/DefaultCacheStore.ts +++ b/packages/javascript/src/DefaultCacheStore.ts @@ -17,47 +17,46 @@ */ export class DefaultCacheStore implements Storage { + private cache: Map; - private cache: Map; + constructor() { + this.cache = new Map(); + } - constructor() { - this.cache = new Map(); - } + public get length(): number { + return this.cache.size; + } - public get length(): number { - return this.cache.size; - } + public getItem(key: string): string | null { + return this.cache.get(key) ?? null; + } - public getItem(key: string): string | null { - return this.cache.get(key) ?? null; - } + public setItem(key: string, value: string): void { + this.cache.set(key, value); + } - public setItem(key: string, value: string): void { - this.cache.set(key, value); - } + public removeItem(key: string): void { + this.cache.delete(key); + } - public removeItem(key: string): void { - this.cache.delete(key); - } + public clear(): void { + this.cache.clear(); + } - public clear(): void { - this.cache.clear(); - } + public key(index: number): string | null { + const keys: string[] = Array.from(this.cache.keys()); + return keys[index] ?? null; + } - public key(index: number): string | null { - const keys = Array.from(this.cache.keys()); - return keys[index] ?? null; - } + public async setData(key: string, value: string): Promise { + this.cache.set(key, value); + } - public async setData(key: string, value: string): Promise { - this.cache.set(key, value); - } + public async getData(key: string): Promise { + return this.cache.get(key) ?? '{}'; + } - public async getData(key: string): Promise { - return this.cache.get(key) ?? "{}"; - } - - public async removeData(key: string): Promise { - this.cache.delete(key); - } + public async removeData(key: string): Promise { + this.cache.delete(key); + } } diff --git a/packages/javascript/src/DefaultCrypto.ts b/packages/javascript/src/DefaultCrypto.ts index 63d005b75..f165c5f2b 100644 --- a/packages/javascript/src/DefaultCrypto.ts +++ b/packages/javascript/src/DefaultCrypto.ts @@ -16,84 +16,60 @@ * under the License. */ -import * as jose from "jose"; -import { JWKInterface } from "./models/crypto"; +import * as jose from 'jose'; +import {Crypto, JWKInterface} from './models/crypto'; -interface CryptoInterface { - base64URLEncode(value: T): string; - base64URLDecode(value: string): string; - hashSha256(data: string): Promise; // Changed to Promise to match implementation - generateRandomBytes(length: number): Uint8Array; - verifyJwt( - idToken: string, - jwk: Partial, - algorithms: string[], - clientId: string, - issuer: string, - subject: string, - clockTolerance?: number, - ): Promise; -} - -export class DefaultCrypto implements CryptoInterface { - - constructor() {} - - /** - * Cross-platform Base64URL encoding using 'jose' utilities - */ - public base64URLEncode(value: Uint8Array | string): string { - const uint8Array = typeof value === "string" - ? new TextEncoder().encode(value) - : value; - - return jose.base64url.encode(uint8Array); - } - - /** - * Cross-platform Base64URL decoding - */ - public base64URLDecode(value: string): string { - const decodedArray = jose.base64url.decode(value); - return new TextDecoder().decode(decodedArray); - } +/** + * Default implementation of the Crypto interface using the 'jose' library + * and the native Web Crypto API. + */ +export class DefaultCrypto implements Crypto { + // eslint-disable-next-line class-methods-use-this + public base64URLDecode(value: string): string { + const decodedArray: Uint8Array = jose.base64url.decode(value); + return new TextDecoder().decode(decodedArray); + } - public async hashSha256(data: string): Promise { - const encoder = new TextEncoder(); - const dataBuffer = encoder.encode(data); + // eslint-disable-next-line class-methods-use-this + public base64URLEncode(value: Uint8Array): string { + return jose.base64url.encode(value); + } - // Using native web crypto (available in modern Node and Browsers) - const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer); - return new Uint8Array(hashBuffer); - } + // eslint-disable-next-line class-methods-use-this + public generateRandomBytes(length: number): Uint8Array { + return crypto.getRandomValues(new Uint8Array(length)); + } - public generateRandomBytes(length: number): Uint8Array { - // globalThis.crypto works in Browsers and Node.js 19+ - const array = new Uint8Array(length); - crypto.getRandomValues(array); - return array; - } + // eslint-disable-next-line class-methods-use-this + public async hashSha256(data: string): Promise { + const encoder: TextEncoder = new TextEncoder(); + const dataBuffer: Uint8Array = encoder.encode(data); + const hashBuffer: ArrayBuffer = await crypto.subtle.digest('SHA-256', dataBuffer); - public async verifyJwt( - idToken: string, - jwk: Partial, - algorithms: string[], - clientId: string, - issuer: string, - subject: string, - clockTolerance?: number, - ): Promise { + return new Uint8Array(hashBuffer); + } - const key = await jose.importJWK(jwk as any); + // eslint-disable-next-line class-methods-use-this + public async verifyJwt( + idToken: string, + jwk: JWKInterface, + algorithms: string[], + clientId: string, + issuer: string, + subject: string, + clockTolerance?: number, + validateJwtIssuer: boolean = true, + ): Promise { + const key: jose.KeyLike | Uint8Array = await jose.importJWK(jwk as jose.JWK); - await jose.jwtVerify(idToken, key, { - algorithms, - audience: clientId, - issuer, - subject, - clockTolerance, - }); + await jose.jwtVerify(idToken, key, { + algorithms, + audience: clientId, + clockTolerance, + issuer: validateJwtIssuer ? issuer : undefined, + subject, + }); - return true; - } + return true; + } } diff --git a/packages/javascript/src/IsomorphicCrypto.ts b/packages/javascript/src/IsomorphicCrypto.ts index 85c744124..c738fc586 100644 --- a/packages/javascript/src/IsomorphicCrypto.ts +++ b/packages/javascript/src/IsomorphicCrypto.ts @@ -44,7 +44,7 @@ export class IsomorphicCrypto { * @returns - code challenge. */ public async getCodeChallenge(verifier: string): Promise { - const hashed = await this.cryptoUtils.hashSha256(verifier); + const hashed: T = await this.cryptoUtils.hashSha256(verifier); return this.cryptoUtils.base64URLEncode(hashed); } diff --git a/packages/javascript/src/index.ts b/packages/javascript/src/index.ts index 7cc97e360..e549d9ea4 100644 --- a/packages/javascript/src/index.ts +++ b/packages/javascript/src/index.ts @@ -149,6 +149,8 @@ export { SignUpOptions, } from './models/config'; export {TokenResponse, IdToken, TokenExchangeRequestConfig} from './models/token'; +export {AgentConfig} from './models/agent'; +export {AuthCodeResponse} from './models/auth-code-response'; export {Crypto, JWKInterface} from './models/crypto'; export {OAuthResponseMode} from './models/oauth-response'; export { diff --git a/packages/javascript/src/models/agent.ts b/packages/javascript/src/models/agent.ts new file mode 100644 index 000000000..abeb657ff --- /dev/null +++ b/packages/javascript/src/models/agent.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Interface representing the configuration for an agent. + */ +export interface AgentConfig { + /** + * The unique identifier for the agent + */ + agentID: string; + /** + * The secret credential for the agent + */ + agentSecret: string; + /** + * The authenticator name to match during the embedded sign-in flow. + * Defaults to {@link AgentConfig.DEFAULT_AUTHENTICATOR_NAME} if not provided. + */ + authenticatorName?: string; +} + +/** + * Namespace that holds constants related to {@link AgentConfig}. + */ +export namespace AgentConfig { + /** + * Default authenticator name used when none is specified. + */ + export const DEFAULT_AUTHENTICATOR_NAME: string = 'Username & Password'; +} diff --git a/packages/javascript/src/models/auth-code-response.ts b/packages/javascript/src/models/auth-code-response.ts new file mode 100644 index 000000000..f3172a369 --- /dev/null +++ b/packages/javascript/src/models/auth-code-response.ts @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Interface representing the authorization code response from the OAuth2/OIDC flow. + */ +export interface AuthCodeResponse { + /** + * The authorization code returned from the authorization endpoint + */ + code: string; + /** + * The session state identifier + */ + session_state: string; + /** + * The state parameter returned from the authorization endpoint + */ + state: string; +} diff --git a/packages/javascript/src/models/crypto.ts b/packages/javascript/src/models/crypto.ts index cd5bffba6..4ecab6e40 100644 --- a/packages/javascript/src/models/crypto.ts +++ b/packages/javascript/src/models/crypto.ts @@ -85,7 +85,7 @@ export interface Crypto { * * @returns Hashed data. */ - hashSha256(data: string): T; + hashSha256(data: string): T | Promise; /** * Verify the provided JWT. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dae95cfc2..ff484d7ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -251,6 +251,9 @@ importers: '@asgardeo/i18n': specifier: workspace:* version: link:../i18n + jose: + specifier: ^5.2.0 + version: 5.10.0 tslib: specifier: 2.8.1 version: 2.8.1 @@ -321,7 +324,7 @@ importers: version: 8.57.0 next: specifier: 15.5.12 - version: 15.5.12(@babel/core@7.27.1)(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.92.1) + version: 15.5.12(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.92.1) prettier: specifier: 2.6.2 version: 2.6.2 @@ -9297,14 +9300,14 @@ snapshots: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6) eslint: 8.57.0 - eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0) - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) - eslint-config-airbnb-typescript: 17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-typescript: 17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) eslint-config-prettier: 8.10.0(eslint@8.57.0) eslint-plugin-eslint-plugin: 5.5.1(eslint@8.57.0) eslint-plugin-header: 3.1.1(eslint@8.57.0) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) - eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.1.6) + eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-node: 11.1.0(eslint@8.57.0) eslint-plugin-prettier: 4.2.5(eslint-config-prettier@8.10.0(eslint@8.57.0))(eslint@8.57.0)(prettier@2.6.2) @@ -10431,6 +10434,15 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0): + dependencies: + confusing-browser-globals: 1.0.11 + eslint: 8.57.0 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) + object.assign: 4.1.7 + object.entries: 1.1.9 + semver: 6.3.1 + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: confusing-browser-globals: 1.0.11 @@ -10440,13 +10452,13 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 - eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0): dependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: @@ -10456,6 +10468,17 @@ snapshots: eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0) + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0): + dependencies: + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) + eslint-plugin-react: 7.37.5(eslint@8.57.0) + eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) + object.assign: 4.1.7 + object.entries: 1.1.9 + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.37.5(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 @@ -10573,12 +10596,12 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.1.6): + eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6): dependencies: '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.1.6) eslint: 8.57.0 optionalDependencies: - '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0)(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6))(eslint@8.57.0)(typescript@5.1.6) transitivePeerDependencies: - supports-color - typescript @@ -11997,7 +12020,7 @@ snapshots: negotiator@1.0.0: {} - next@15.5.12(@babel/core@7.27.1)(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.92.1): + next@15.5.12(@playwright/test@1.58.2)(react-dom@19.1.4(react@19.1.4))(react@19.1.4)(sass@1.92.1): dependencies: '@next/env': 15.5.12 '@swc/helpers': 0.5.15 @@ -12005,7 +12028,7 @@ snapshots: postcss: 8.4.31 react: 19.1.4 react-dom: 19.1.4(react@19.1.4) - styled-jsx: 5.1.6(@babel/core@7.27.1)(react@19.1.4) + styled-jsx: 5.1.6(react@19.1.4) optionalDependencies: '@next/swc-darwin-arm64': 15.5.12 '@next/swc-darwin-x64': 15.5.12 @@ -13356,12 +13379,10 @@ snapshots: style-search@0.1.0: {} - styled-jsx@5.1.6(@babel/core@7.27.1)(react@19.1.4): + styled-jsx@5.1.6(react@19.1.4): dependencies: client-only: 0.0.1 react: 19.1.4 - optionalDependencies: - '@babel/core': 7.27.1 stylehacks@5.1.1(postcss@8.4.31): dependencies: @@ -14051,7 +14072,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.15.3 - '@vitest/browser': 3.1.3(playwright@1.55.1)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) + '@vitest/browser': 3.1.3(playwright@1.58.2)(vite@6.4.1(@types/node@22.15.3)(jiti@2.6.0)(lightningcss@1.30.1)(sass-embedded@1.92.1)(sass@1.92.1)(terser@5.39.2)(tsx@4.21.0)(yaml@2.8.0))(vitest@3.1.3) jsdom: 27.4.0 transitivePeerDependencies: - jiti