@caido/server-auth 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/index.cjs +179 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -71
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +62 -71
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +177 -118
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["Client","fetchExchange"],"sources":["../src/errors.ts","../src/queries.ts","../src/client.ts","../src/approvers/browser.ts","../src/approvers/pat.ts"],"sourcesContent":["/**\n * Base error class for authentication-related errors.\n */\nexport class AuthenticationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Error thrown when the authentication flow fails to start.\n */\nexport class AuthenticationFlowError extends AuthenticationError {\n /** Error code from the API */\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(`${code}: ${message}`);\n this.name = \"AuthenticationFlowError\";\n this.code = code;\n }\n}\n\n/**\n * Error thrown when token refresh fails.\n */\nexport class TokenRefreshError extends AuthenticationError {\n /** Error code from the API */\n readonly code: string;\n\n constructor(code: string, message: string) {\n super(`${code}: ${message}`);\n this.name = \"TokenRefreshError\";\n this.code = code;\n }\n}\n\n/**\n * Error thrown when device approval fails.\n */\nexport class DeviceApprovalError extends AuthenticationError {\n /** HTTP status code if available */\n readonly statusCode: number | undefined;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = \"DeviceApprovalError\";\n this.statusCode = statusCode;\n }\n}\n\n/**\n * Error thrown when fetching device information fails.\n */\nexport class DeviceInformationError extends AuthenticationError {\n /** HTTP status code if available */\n readonly statusCode: number | undefined;\n\n constructor(message: string, statusCode?: number) {\n super(message);\n this.name = \"DeviceInformationError\";\n this.statusCode = statusCode;\n }\n}\n","import type { DocumentNode } from \"graphql\";\nimport { gql } from \"graphql-tag\";\n\nexport const START_AUTHENTICATION_FLOW: DocumentNode = gql`\n mutation StartAuthenticationFlow {\n startAuthenticationFlow {\n request {\n id\n userCode\n verificationUrl\n expiresAt\n }\n error {\n code\n message\n }\n }\n }\n`;\n\nexport const CREATED_AUTHENTICATION_TOKEN: DocumentNode = gql`\n subscription CreatedAuthenticationToken($requestId: ID!) {\n createdAuthenticationToken(requestId: $requestId) {\n token {\n accessToken\n refreshToken\n expiresAt\n }\n error {\n code\n message\n }\n }\n }\n`;\n\nexport const REFRESH_AUTHENTICATION_TOKEN: DocumentNode = gql`\n mutation RefreshAuthenticationToken($refreshToken: String!) {\n refreshAuthenticationToken(refreshToken: $refreshToken) {\n token {\n accessToken\n refreshToken\n expiresAt\n }\n error {\n code\n message\n }\n }\n }\n`;\n","import { Client, fetchExchange } from \"@urql/core\";\nimport { createClient as createWSClient } from \"graphql-ws\";\n\nimport type { AuthApprover } from \"./approvers/types.js\";\nimport {\n AuthenticationError,\n AuthenticationFlowError,\n TokenRefreshError,\n} from \"./errors.js\";\nimport {\n CREATED_AUTHENTICATION_TOKEN,\n REFRESH_AUTHENTICATION_TOKEN,\n START_AUTHENTICATION_FLOW,\n} from \"./queries.js\";\nimport type {\n AuthenticationRequest,\n AuthenticationToken,\n CreatedAuthenticationTokenResponse,\n RefreshAuthenticationTokenResponse,\n StartAuthenticationFlowResponse,\n} from \"./types.js\";\n\n/**\n * Client for authenticating with a Caido instance.\n *\n * @example\n * ```typescript\n * import { CaidoAuth, BrowserApprover } from \"@caido/auth\";\n *\n * const auth = new CaidoAuth(\n * \"http://localhost:8080\",\n * new BrowserApprover((request) => {\n * console.log(`Visit ${request.verificationUrl}`);\n * })\n * );\n *\n * const token = await auth.startAuthenticationFlow();\n * console.log(\"Access token:\", token.accessToken);\n * ```\n */\nexport class CaidoAuth {\n private readonly instanceUrl: string;\n private readonly graphqlUrl: string;\n private readonly websocketUrl: string;\n private readonly approver: AuthApprover;\n private readonly client: Client;\n\n /**\n * Create a new CaidoAuth client.\n *\n * @param instanceUrl - Base URL of the Caido instance (e.g., \"http://localhost:8080\")\n * @param approver - The approver to use for the authentication flow\n */\n constructor(instanceUrl: string, approver: AuthApprover) {\n this.instanceUrl = instanceUrl.replace(/\\/$/, \"\");\n this.graphqlUrl = `${this.instanceUrl}/graphql`;\n this.websocketUrl = this.getWebsocketUrl();\n this.approver = approver;\n\n this.client = new Client({\n url: this.graphqlUrl,\n exchanges: [fetchExchange],\n });\n }\n\n /**\n * Convert HTTP(S) URL to WS(S) URL for subscriptions.\n */\n private getWebsocketUrl(): string {\n const url = new URL(this.graphqlUrl);\n const scheme = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return `${scheme}//${url.host}/ws/graphql`;\n }\n\n /**\n * Start the device code authentication flow.\n *\n * This method:\n * 1. Initiates the authentication flow via GraphQL mutation\n * 2. Calls the approver with the authentication request\n * 3. Waits for the user to authorize via WebSocket subscription\n * 4. Returns the authentication token once approved\n *\n * @returns The authentication token\n * @throws {AuthenticationFlowError} If the flow fails to start\n * @throws {AuthenticationError} If token retrieval fails\n */\n async startAuthenticationFlow(): Promise<AuthenticationToken> {\n // Step 1: Start the authentication flow\n const result = await this.client\n .mutation<StartAuthenticationFlowResponse>(START_AUTHENTICATION_FLOW, {})\n .toPromise();\n\n if (result.error) {\n throw new AuthenticationFlowError(\"GRAPHQL_ERROR\", result.error.message);\n }\n\n const payload = result.data?.startAuthenticationFlow;\n if (!payload) {\n throw new AuthenticationFlowError(\n \"NO_RESPONSE\",\n \"No response from startAuthenticationFlow\",\n );\n }\n\n if (payload.error) {\n throw new AuthenticationFlowError(\n payload.error.code,\n payload.error.message,\n );\n }\n\n if (!payload.request) {\n throw new AuthenticationFlowError(\n \"NO_REQUEST\",\n \"No authentication request returned\",\n );\n }\n\n const authRequest: AuthenticationRequest = {\n id: payload.request.id,\n userCode: payload.request.userCode,\n verificationUrl: payload.request.verificationUrl,\n expiresAt: new Date(payload.request.expiresAt),\n };\n\n // Step 2: Call the approver\n await this.approver.approve(authRequest);\n\n // Step 3: Wait for the token via subscription\n const token = await this.waitForToken(authRequest.id);\n return token;\n }\n\n /**\n * Subscribe and wait for the authentication token.\n *\n * @param requestId - The authentication request ID\n * @returns The authentication token once the user authorizes\n * @throws {AuthenticationError} If subscription fails or returns an error\n */\n private async waitForToken(requestId: string): Promise<AuthenticationToken> {\n return new Promise<AuthenticationToken>((resolve, reject) => {\n const wsClient = createWSClient({\n url: this.websocketUrl,\n });\n\n const unsubscribe =\n wsClient.subscribe<CreatedAuthenticationTokenResponse>(\n {\n query:\n CREATED_AUTHENTICATION_TOKEN.loc?.source.body ??\n `subscription CreatedAuthenticationToken($requestId: ID!) {\n createdAuthenticationToken(requestId: $requestId) {\n token { accessToken refreshToken expiresAt }\n error { code message }\n }\n }`,\n variables: { requestId },\n },\n {\n next: (result) => {\n const payload = result.data?.createdAuthenticationToken;\n\n if (payload?.error) {\n unsubscribe();\n wsClient.dispose();\n reject(\n new AuthenticationError(\n `${payload.error.code}: ${payload.error.message}`,\n ),\n );\n return;\n }\n\n if (payload?.token) {\n unsubscribe();\n wsClient.dispose();\n resolve({\n accessToken: payload.token.accessToken,\n refreshToken: payload.token.refreshToken,\n expiresAt: new Date(payload.token.expiresAt),\n });\n }\n },\n error: (error) => {\n wsClient.dispose();\n reject(\n new AuthenticationError(\n error instanceof Error ? error.message : String(error),\n ),\n );\n },\n complete: () => {\n wsClient.dispose();\n reject(\n new AuthenticationError(\n \"Subscription ended without receiving token\",\n ),\n );\n },\n },\n );\n });\n }\n\n /**\n * Refresh an access token using a refresh token.\n *\n * @param refreshToken - The refresh token from a previous authentication\n * @returns New authentication token with updated access and refresh tokens\n * @throws {TokenRefreshError} If the refresh fails\n */\n async refreshToken(refreshToken: string): Promise<AuthenticationToken> {\n const result = await this.client\n .mutation<RefreshAuthenticationTokenResponse>(\n REFRESH_AUTHENTICATION_TOKEN,\n { refreshToken },\n )\n .toPromise();\n\n if (result.error) {\n throw new TokenRefreshError(\"GRAPHQL_ERROR\", result.error.message);\n }\n\n const payload = result.data?.refreshAuthenticationToken;\n if (!payload) {\n throw new TokenRefreshError(\n \"NO_RESPONSE\",\n \"No response from refreshAuthenticationToken\",\n );\n }\n\n if (payload.error) {\n throw new TokenRefreshError(payload.error.code, payload.error.message);\n }\n\n if (!payload.token) {\n throw new TokenRefreshError(\"NO_TOKEN\", \"No token returned from refresh\");\n }\n\n return {\n accessToken: payload.token.accessToken,\n refreshToken: payload.token.refreshToken,\n expiresAt: new Date(payload.token.expiresAt),\n };\n }\n}\n","import type { AuthenticationRequest } from \"../types.js\";\n\nimport type { AuthApprover } from \"./types.js\";\n\n/**\n * Callback function that receives the authentication request details.\n * Used to display the verification URL and user code to the user.\n */\nexport type OnRequestCallback = (\n request: AuthenticationRequest,\n) => Promise<void> | void;\n\n/**\n * Browser-based approver that delegates to a callback function.\n * The callback should display the verification URL and user code to the user,\n * who then manually approves the request in their browser.\n *\n * @example\n * ```typescript\n * const approver = new BrowserApprover((request) => {\n * console.log(`Visit ${request.verificationUrl}`);\n * });\n * ```\n */\nexport class BrowserApprover implements AuthApprover {\n private readonly onRequest: OnRequestCallback;\n\n /**\n * Create a new BrowserApprover.\n *\n * @param onRequest - Callback function that will be called with the authentication request\n */\n constructor(onRequest: OnRequestCallback) {\n this.onRequest = onRequest;\n }\n\n /**\n * Approve the authentication request by calling the callback.\n * The actual approval happens when the user visits the URL and enters the code.\n *\n * @param request - The authentication request\n */\n async approve(request: AuthenticationRequest): Promise<void> {\n await this.onRequest(request);\n }\n}\n","import { DeviceApprovalError, DeviceInformationError } from \"../errors.js\";\nimport type { AuthenticationRequest, DeviceInformation } from \"../types.js\";\n\nimport type { AuthApprover } from \"./types.js\";\n\nconst DEFAULT_API_URL = \"https://api.caido.io\";\n\n/**\n * Options for the PATApprover.\n */\nexport interface PATApproverOptions {\n /** The Personal Access Token to use for approval */\n pat: string;\n /** If provided, only approve these scopes. Others will be filtered out. */\n allowedScopes?: string[];\n /** The API URL to use. Defaults to \"https://api.caido.io\" */\n apiUrl?: string;\n}\n\n/**\n * PAT-based approver that automatically approves device code requests.\n * Uses a Personal Access Token to call the Caido API directly.\n *\n * @example\n * ```typescript\n * // Approve all scopes\n * const approver = new PATApprover({ pat: \"caido_xxxxx\" });\n *\n * // Approve only specific scopes\n * const limitedApprover = new PATApprover({\n * pat: \"caido_xxxxx\",\n * allowedScopes: [\"read:projects\", \"write:requests\"],\n * });\n * ```\n */\nexport class PATApprover implements AuthApprover {\n private readonly pat: string;\n private readonly allowedScopes: string[] | undefined;\n private readonly apiUrl: string;\n\n /**\n * Create a new PATApprover.\n *\n * @param options - Configuration options for the approver\n */\n constructor(options: PATApproverOptions) {\n this.pat = options.pat;\n this.allowedScopes = options.allowedScopes;\n this.apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\\/$/, \"\");\n }\n\n /**\n * Approve the authentication request using the PAT.\n * First fetches device information to get available scopes,\n * then filters scopes if allowedScopes is set,\n * and finally approves the device.\n *\n * @param request - The authentication request\n * @throws {DeviceInformationError} If fetching device information fails\n * @throws {DeviceApprovalError} If approving the device fails\n */\n async approve(request: AuthenticationRequest): Promise<void> {\n // Step 1: Get device information to retrieve available scopes\n const deviceInfo = await this.getDeviceInformation(request.userCode);\n\n // Step 2: Filter scopes if allowedScopes is provided\n let scopesToApprove = deviceInfo.scopes.map((s) => s.name);\n if (this.allowedScopes) {\n scopesToApprove = scopesToApprove.filter((scope) =>\n this.allowedScopes!.includes(scope),\n );\n }\n\n // Step 3: Approve the device with the filtered scopes\n await this.approveDevice(request.userCode, scopesToApprove);\n }\n\n /**\n * Fetch device information from the API.\n *\n * @param userCode - The user code from the authentication request\n * @returns The device information including available scopes\n * @throws {DeviceInformationError} If the request fails\n */\n private async getDeviceInformation(\n userCode: string,\n ): Promise<DeviceInformation> {\n const params = new URLSearchParams();\n params.append(\"user_code\", userCode);\n const url = new URL(`${this.apiUrl}/oauth2/device/information`);\n url.search = params.toString();\n\n const response = await fetch(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${this.pat}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n throw new DeviceInformationError(\n `Failed to get device information: ${errorText}`,\n response.status,\n );\n }\n\n const data = (await response.json()) as DeviceInformation;\n return data;\n }\n\n /**\n * Approve the device with the specified scopes.\n *\n * @param userCode - The user code from the authentication request\n * @param scopes - The scopes to approve\n * @throws {DeviceApprovalError} If the request fails\n */\n private async approveDevice(\n userCode: string,\n scopes: string[],\n ): Promise<void> {\n const params = new URLSearchParams();\n params.append(\"user_code\", userCode);\n params.append(\"scope\", scopes.join(\",\"));\n const url = new URL(`${this.apiUrl}/oauth2/device/approve`);\n url.search = params.toString();\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.pat}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => \"Unknown error\");\n throw new DeviceApprovalError(\n `Failed to approve device: ${errorText}`,\n response.status,\n );\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Client","fetchExchange"],"sources":["../src/errors.ts","../src/queries.ts","../src/client.ts","../src/approvers/browser.ts","../src/approvers/pat.ts"],"sourcesContent":["/**\n * Base error class for authentication-related errors.\n */\nexport class AuthenticationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AuthenticationError\";\n }\n}\n\n/**\n * Error thrown for errors coming from the Caido cloud API.\n * Used for device approval and device information operations.\n */\nexport class CloudError extends AuthenticationError {\n /** HTTP status code if available */\n readonly statusCode: number | undefined;\n /** Error code from the API if available */\n readonly code: string | undefined;\n /** Reason for the error if available */\n readonly reason: string | undefined;\n\n constructor(\n message: string,\n options?: {\n statusCode?: number;\n code?: string;\n reason?: string;\n },\n ) {\n super(message);\n this.name = \"CloudError\";\n this.statusCode = options?.statusCode;\n this.code = options?.code;\n this.reason = options?.reason;\n }\n}\n\n/**\n * Error thrown for errors coming from the Caido instance.\n * Used for authentication flow and token refresh operations.\n */\nexport class InstanceError extends AuthenticationError {\n /** Error code from the API */\n readonly code: string;\n /** Reason for the error if available */\n readonly reason: string | undefined;\n /** Error message if available */\n readonly errorMessage: string | undefined;\n\n constructor(\n code: string,\n options?: {\n reason?: string;\n message?: string;\n },\n ) {\n const message = options?.reason ?? options?.message ?? code;\n super(message);\n this.name = \"InstanceError\";\n this.code = code;\n this.reason = options?.reason;\n this.errorMessage = options?.message;\n }\n}\n","import type { DocumentNode } from \"graphql\";\nimport { gql } from \"graphql-tag\";\n\nexport const START_AUTHENTICATION_FLOW: DocumentNode = gql`\n mutation StartAuthenticationFlow {\n startAuthenticationFlow {\n request {\n id\n userCode\n verificationUrl\n expiresAt\n }\n error {\n ... on AuthenticationUserError {\n code\n reason\n }\n ... on CloudUserError {\n code\n reason\n }\n ... on InternalUserError {\n code\n message\n }\n ... on OtherUserError {\n code\n }\n }\n }\n }\n`;\n\nexport const CREATED_AUTHENTICATION_TOKEN: DocumentNode = gql`\n subscription CreatedAuthenticationToken($requestId: ID!) {\n createdAuthenticationToken(requestId: $requestId) {\n token {\n accessToken\n expiresAt\n refreshToken\n scopes\n }\n error {\n ... on AuthenticationUserError {\n code\n reason\n }\n ... on InternalUserError {\n code\n message\n }\n ... on OtherUserError {\n code\n }\n }\n }\n }\n`;\n\nexport const REFRESH_AUTHENTICATION_TOKEN: DocumentNode = gql`\n mutation RefreshAuthenticationToken($refreshToken: Token!) {\n refreshAuthenticationToken(refreshToken: $refreshToken) {\n token {\n accessToken\n expiresAt\n refreshToken\n scopes\n }\n error {\n ... on AuthenticationUserError {\n code\n reason\n }\n ... on CloudUserError {\n code\n reason\n }\n ... on InternalUserError {\n code\n message\n }\n ... on OtherUserError {\n code\n }\n }\n }\n }\n`;\n","import { Client, fetchExchange } from \"@urql/core\";\nimport { print } from \"graphql\";\nimport { createClient as createWSClient } from \"graphql-ws\";\n\nimport type { AuthApprover } from \"./approvers/types.js\";\nimport { AuthenticationError, InstanceError } from \"./errors.js\";\nimport {\n CREATED_AUTHENTICATION_TOKEN,\n REFRESH_AUTHENTICATION_TOKEN,\n START_AUTHENTICATION_FLOW,\n} from \"./queries.js\";\nimport type {\n AuthenticationRequest,\n AuthenticationToken,\n CreatedAuthenticationTokenError,\n CreatedAuthenticationTokenResponse,\n RefreshAuthenticationTokenError,\n RefreshAuthenticationTokenResponse,\n StartAuthenticationFlowError,\n StartAuthenticationFlowResponse,\n} from \"./types.js\";\n\n/**\n * Options for configuring the AuthClient.\n */\nexport interface AuthClientOptions {\n /** Base URL of the Caido instance (e.g., \"http://localhost:8080\") */\n instanceUrl: string;\n /** The approver to use for the authentication flow */\n approver: AuthApprover;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Custom fetch implementation */\n fetch?: typeof globalThis.fetch;\n}\n\ninterface ErrorDetails {\n reason?: string;\n message?: string;\n}\n\n/**\n * Client for authenticating with a Caido instance.\n *\n * @example\n * ```typescript\n * import { AuthClient, BrowserApprover } from \"@caido/auth\";\n *\n * const auth = new AuthClient({\n * instanceUrl: \"http://localhost:8080\",\n * approver: new BrowserApprover((request) => {\n * console.log(`Visit ${request.verificationUrl}`);\n * })\n * });\n *\n * const token = await auth.startAuthenticationFlow();\n * console.log(\"Access token:\", token.accessToken);\n * ```\n */\nexport class AuthClient {\n private readonly instanceUrl: string;\n private readonly graphqlUrl: string;\n private readonly websocketUrl: string;\n private readonly approver: AuthApprover;\n private readonly client: Client;\n private readonly fetchFn: typeof globalThis.fetch | undefined;\n private readonly timeout: number | undefined;\n\n constructor(options: AuthClientOptions) {\n this.instanceUrl = options.instanceUrl.replace(/\\/$/, \"\");\n this.graphqlUrl = `${this.instanceUrl}/graphql`;\n this.websocketUrl = this.getWebsocketUrl();\n this.approver = options.approver;\n this.fetchFn = options.fetch;\n this.timeout = options.timeout;\n\n this.client = new Client({\n url: this.graphqlUrl,\n exchanges: [fetchExchange],\n fetchOptions: () => {\n const fetchOptions: RequestInit = {};\n if (this.timeout !== undefined) {\n fetchOptions.signal = AbortSignal.timeout(this.timeout);\n }\n return fetchOptions;\n },\n fetch: this.fetchFn,\n });\n }\n\n private getWebsocketUrl(): string {\n const url = new URL(this.graphqlUrl);\n const scheme = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return `${scheme}//${url.host}/ws/graphql`;\n }\n\n private extractErrorDetails(\n error:\n | StartAuthenticationFlowError\n | CreatedAuthenticationTokenError\n | RefreshAuthenticationTokenError,\n ): ErrorDetails {\n if (\"reason\" in error) {\n return { reason: error.reason };\n }\n if (\"message\" in error) {\n return { message: error.message };\n }\n return {};\n }\n\n /**\n * Start the device code authentication flow.\n *\n * This method:\n * 1. Initiates the authentication flow via GraphQL mutation\n * 2. Calls the approver with the authentication request\n * 3. Waits for the user to authorize via WebSocket subscription\n * 4. Returns the authentication token once approved\n *\n * @returns The authentication token\n * @throws {InstanceError} If the flow fails to start\n * @throws {AuthenticationError} If token retrieval fails\n */\n async startAuthenticationFlow(): Promise<AuthenticationToken> {\n // Step 1: Start the authentication flow\n const result = await this.client\n .mutation<StartAuthenticationFlowResponse>(START_AUTHENTICATION_FLOW, {})\n .toPromise();\n\n if (result.error) {\n throw new InstanceError(\"GRAPHQL_ERROR\", {\n message: result.error.message,\n });\n }\n\n const payload = result.data?.startAuthenticationFlow;\n if (!payload) {\n throw new InstanceError(\"NO_RESPONSE\", {\n message: \"No response from startAuthenticationFlow\",\n });\n }\n\n if (payload.error) {\n const details = this.extractErrorDetails(payload.error);\n throw new InstanceError(payload.error.code, details);\n }\n\n if (!payload.request) {\n throw new InstanceError(\"NO_REQUEST\", {\n message: \"No authentication request returned\",\n });\n }\n\n const authRequest: AuthenticationRequest = {\n id: payload.request.id,\n userCode: payload.request.userCode,\n verificationUrl: payload.request.verificationUrl,\n expiresAt: new Date(payload.request.expiresAt),\n };\n\n // Step 2: Call the approver\n await this.approver.approve(authRequest);\n\n // Step 3: Wait for the token via subscription\n const token = await this.waitForToken(authRequest.id);\n return token;\n }\n\n private async waitForToken(requestId: string): Promise<AuthenticationToken> {\n return new Promise<AuthenticationToken>((resolve, reject) => {\n const wsClient = createWSClient({\n url: this.websocketUrl,\n });\n\n const unsubscribe =\n wsClient.subscribe<CreatedAuthenticationTokenResponse>(\n {\n query: print(CREATED_AUTHENTICATION_TOKEN),\n variables: { requestId },\n },\n {\n next: (result) => {\n const payload = result.data?.createdAuthenticationToken;\n\n if (payload?.error) {\n unsubscribe();\n wsClient.dispose();\n const details = this.extractErrorDetails(payload.error);\n reject(new InstanceError(payload.error.code, details));\n return;\n }\n\n if (payload?.token) {\n unsubscribe();\n wsClient.dispose();\n resolve({\n accessToken: payload.token.accessToken,\n refreshToken: payload.token.refreshToken,\n expiresAt: new Date(payload.token.expiresAt),\n scopes: payload.token.scopes,\n });\n }\n },\n error: (error) => {\n wsClient.dispose();\n reject(\n new InstanceError(\"SUBSCRIPTION_ERROR\", {\n message:\n error instanceof Error ? error.message : String(error),\n }),\n );\n },\n complete: () => {\n wsClient.dispose();\n reject(\n new InstanceError(\"SUBSCRIPTION_COMPLETE\", {\n message: \"Subscription ended without receiving token\",\n }),\n );\n },\n },\n );\n });\n }\n\n /**\n * Refresh an access token using a refresh token.\n *\n * @param refreshToken - The refresh token from a previous authentication\n * @returns New authentication token with updated access and refresh tokens\n * @throws {InstanceError} If the refresh fails\n */\n async refreshToken(refreshToken: string): Promise<AuthenticationToken> {\n const result = await this.client\n .mutation<RefreshAuthenticationTokenResponse>(\n REFRESH_AUTHENTICATION_TOKEN,\n { refreshToken },\n )\n .toPromise();\n\n if (result.error) {\n throw new InstanceError(\"GRAPHQL_ERROR\", {\n message: result.error.message,\n });\n }\n\n const payload = result.data?.refreshAuthenticationToken;\n if (!payload) {\n throw new InstanceError(\"NO_RESPONSE\", {\n message: \"No response from refreshAuthenticationToken\",\n });\n }\n\n if (payload.error) {\n const details = this.extractErrorDetails(payload.error);\n throw new InstanceError(payload.error.code, details);\n }\n\n if (!payload.token) {\n throw new InstanceError(\"NO_TOKEN\", {\n message: \"No token returned from refresh\",\n });\n }\n\n return {\n accessToken: payload.token.accessToken,\n refreshToken: payload.token.refreshToken,\n expiresAt: new Date(payload.token.expiresAt),\n scopes: payload.token.scopes,\n };\n }\n}\n","import type { AuthenticationRequest } from \"../types.js\";\n\nimport type { AuthApprover } from \"./types.js\";\n\n/**\n * Callback function that receives the authentication request details.\n * Used to display the verification URL and user code to the user.\n */\nexport type OnRequestCallback = (\n request: AuthenticationRequest,\n) => Promise<void> | void;\n\n/**\n * Browser-based approver that delegates to a callback function.\n * The callback should display the verification URL and user code to the user,\n * who then manually approves the request in their browser.\n *\n * @example\n * ```typescript\n * const approver = new BrowserApprover((request) => {\n * console.log(`Visit ${request.verificationUrl}`);\n * });\n * ```\n */\nexport class BrowserApprover implements AuthApprover {\n private readonly onRequest: OnRequestCallback;\n\n /**\n * Create a new BrowserApprover.\n *\n * @param onRequest - Callback function that will be called with the authentication request\n */\n constructor(onRequest: OnRequestCallback) {\n this.onRequest = onRequest;\n }\n\n /**\n * Approve the authentication request by calling the callback.\n * The actual approval happens when the user visits the URL and enters the code.\n *\n * @param request - The authentication request\n */\n async approve(request: AuthenticationRequest): Promise<void> {\n await this.onRequest(request);\n }\n}\n","import { CloudError } from \"../errors.js\";\nimport type { AuthenticationRequest, DeviceInformation } from \"../types.js\";\n\nimport type { AuthApprover } from \"./types.js\";\n\nconst DEFAULT_API_URL = \"https://api.caido.io\";\n\ninterface OAuth2ErrorResponse {\n error?: string;\n error_description?: string;\n}\n\ntype OAuth2ErrorData = OAuth2ErrorResponse | string;\n\ninterface ParsedOAuth2Error {\n errorText: string;\n errorCode: string | undefined;\n errorDescription: string | undefined;\n}\n\ninterface RequestOptions {\n method: string;\n headers: Record<string, string>;\n}\n\n/**\n * Options for the PATApprover.\n */\nexport interface PATApproverOptions {\n /** The Personal Access Token to use for approval */\n pat: string;\n /** If provided, only approve these scopes. Others will be filtered out. */\n allowedScopes?: string[];\n /** The API URL to use. Defaults to \"https://api.caido.io\" */\n apiUrl?: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /** Custom fetch implementation */\n fetch?: typeof globalThis.fetch;\n}\n\n/**\n * PAT-based approver that automatically approves device code requests.\n * Uses a Personal Access Token to call the Caido API directly.\n *\n * @example\n * ```typescript\n * // Approve all scopes\n * const approver = new PATApprover({ pat: \"caido_xxxxx\" });\n *\n * // Approve only specific scopes\n * const limitedApprover = new PATApprover({\n * pat: \"caido_xxxxx\",\n * allowedScopes: [\"read:projects\", \"write:requests\"],\n * });\n * ```\n */\nexport class PATApprover implements AuthApprover {\n private readonly pat: string;\n private readonly allowedScopes: string[] | undefined;\n private readonly apiUrl: string;\n private readonly fetchFn: typeof globalThis.fetch;\n private readonly timeout: number | undefined;\n\n constructor(options: PATApproverOptions) {\n this.pat = options.pat;\n this.allowedScopes = options.allowedScopes;\n this.apiUrl = (options.apiUrl ?? DEFAULT_API_URL).replace(/\\/$/, \"\");\n this.fetchFn = options.fetch ?? globalThis.fetch;\n this.timeout = options.timeout;\n }\n\n /**\n * Approve the authentication request using the PAT.\n * First fetches device information to get available scopes,\n * then filters scopes if allowedScopes is set,\n * and finally approves the device.\n *\n * @param request - The authentication request\n * @throws {CloudError} If fetching device information or approving the device fails\n */\n async approve(request: AuthenticationRequest): Promise<void> {\n // Step 1: Get device information to retrieve available scopes\n const deviceInfo = await this.getDeviceInformation(request.userCode);\n\n // Step 2: Filter scopes if allowedScopes is provided\n let scopesToApprove = deviceInfo.scopes.map((s) => s.name);\n if (this.allowedScopes) {\n scopesToApprove = scopesToApprove.filter((scope) =>\n this.allowedScopes!.includes(scope),\n );\n }\n\n // Step 3: Approve the device with the filtered scopes\n await this.approveDevice(request.userCode, scopesToApprove);\n }\n\n private async sendRequest(\n url: URL,\n options: RequestOptions,\n ): Promise<Response> {\n const fetchOptions: RequestInit = {\n method: options.method,\n headers: options.headers,\n };\n\n if (this.timeout !== undefined) {\n fetchOptions.signal = AbortSignal.timeout(this.timeout);\n }\n\n return this.fetchFn(url, fetchOptions);\n }\n\n private async parseOAuth2Error(\n response: Response,\n ): Promise<ParsedOAuth2Error> {\n let errorText: string;\n let errorCode: string | undefined;\n let errorDescription: string | undefined;\n\n try {\n const errorData = (await response.json()) as OAuth2ErrorData;\n if (typeof errorData === \"string\") {\n errorText = errorData;\n } else {\n errorCode = errorData.error;\n errorDescription = errorData.error_description;\n errorText = errorDescription ?? errorCode ?? \"Unknown error\";\n }\n } catch {\n errorText = await response.text().catch(() => \"Unknown error\");\n }\n\n return { errorText, errorCode, errorDescription };\n }\n\n private async getDeviceInformation(\n userCode: string,\n ): Promise<DeviceInformation> {\n const params = new URLSearchParams();\n params.append(\"user_code\", userCode);\n const url = new URL(`${this.apiUrl}/oauth2/device/information`);\n url.search = params.toString();\n\n const response = await this.sendRequest(url, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${this.pat}`,\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const { errorText, errorCode, errorDescription } =\n await this.parseOAuth2Error(response);\n\n throw new CloudError(`Failed to get device information: ${errorText}`, {\n statusCode: response.status,\n code: errorCode,\n reason: errorDescription,\n });\n }\n\n const data = (await response.json()) as DeviceInformation;\n return data;\n }\n\n private async approveDevice(\n userCode: string,\n scopes: string[],\n ): Promise<void> {\n const params = new URLSearchParams();\n params.append(\"user_code\", userCode);\n params.append(\"scope\", scopes.join(\",\"));\n const url = new URL(`${this.apiUrl}/oauth2/device/approve`);\n url.search = params.toString();\n\n const response = await this.sendRequest(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.pat}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const { errorText, errorCode, errorDescription } =\n await this.parseOAuth2Error(response);\n\n throw new CloudError(`Failed to approve device: ${errorText}`, {\n statusCode: response.status,\n code: errorCode,\n reason: errorDescription,\n });\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -23,6 +23,8 @@ interface AuthenticationToken {
|
|
|
23
23
|
refreshToken: string;
|
|
24
24
|
/** When the access token expires */
|
|
25
25
|
expiresAt: Date;
|
|
26
|
+
/** The scopes granted to this token */
|
|
27
|
+
scopes: string[];
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Scope information returned from device information endpoint.
|
|
@@ -61,40 +63,47 @@ interface AuthApprover {
|
|
|
61
63
|
//#endregion
|
|
62
64
|
//#region src/client.d.ts
|
|
63
65
|
/**
|
|
66
|
+
* Options for configuring the AuthClient.
|
|
67
|
+
*/
|
|
68
|
+
interface AuthClientOptions {
|
|
69
|
+
/** Base URL of the Caido instance (e.g., "http://localhost:8080") */
|
|
70
|
+
instanceUrl: string;
|
|
71
|
+
/** The approver to use for the authentication flow */
|
|
72
|
+
approver: AuthApprover;
|
|
73
|
+
/** Request timeout in milliseconds */
|
|
74
|
+
timeout?: number;
|
|
75
|
+
/** Custom fetch implementation */
|
|
76
|
+
fetch?: typeof globalThis.fetch;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
64
79
|
* Client for authenticating with a Caido instance.
|
|
65
80
|
*
|
|
66
81
|
* @example
|
|
67
82
|
* ```typescript
|
|
68
|
-
* import {
|
|
83
|
+
* import { AuthClient, BrowserApprover } from "@caido/auth";
|
|
69
84
|
*
|
|
70
|
-
* const auth = new
|
|
71
|
-
* "http://localhost:8080",
|
|
72
|
-
* new BrowserApprover((request) => {
|
|
85
|
+
* const auth = new AuthClient({
|
|
86
|
+
* instanceUrl: "http://localhost:8080",
|
|
87
|
+
* approver: new BrowserApprover((request) => {
|
|
73
88
|
* console.log(`Visit ${request.verificationUrl}`);
|
|
74
89
|
* })
|
|
75
|
-
* );
|
|
90
|
+
* });
|
|
76
91
|
*
|
|
77
92
|
* const token = await auth.startAuthenticationFlow();
|
|
78
93
|
* console.log("Access token:", token.accessToken);
|
|
79
94
|
* ```
|
|
80
95
|
*/
|
|
81
|
-
declare class
|
|
96
|
+
declare class AuthClient {
|
|
82
97
|
private readonly instanceUrl;
|
|
83
98
|
private readonly graphqlUrl;
|
|
84
99
|
private readonly websocketUrl;
|
|
85
100
|
private readonly approver;
|
|
86
101
|
private readonly client;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
* @param instanceUrl - Base URL of the Caido instance (e.g., "http://localhost:8080")
|
|
91
|
-
* @param approver - The approver to use for the authentication flow
|
|
92
|
-
*/
|
|
93
|
-
constructor(instanceUrl: string, approver: AuthApprover);
|
|
94
|
-
/**
|
|
95
|
-
* Convert HTTP(S) URL to WS(S) URL for subscriptions.
|
|
96
|
-
*/
|
|
102
|
+
private readonly fetchFn;
|
|
103
|
+
private readonly timeout;
|
|
104
|
+
constructor(options: AuthClientOptions);
|
|
97
105
|
private getWebsocketUrl;
|
|
106
|
+
private extractErrorDetails;
|
|
98
107
|
/**
|
|
99
108
|
* Start the device code authentication flow.
|
|
100
109
|
*
|
|
@@ -105,24 +114,17 @@ declare class CaidoAuth {
|
|
|
105
114
|
* 4. Returns the authentication token once approved
|
|
106
115
|
*
|
|
107
116
|
* @returns The authentication token
|
|
108
|
-
* @throws {
|
|
117
|
+
* @throws {InstanceError} If the flow fails to start
|
|
109
118
|
* @throws {AuthenticationError} If token retrieval fails
|
|
110
119
|
*/
|
|
111
120
|
startAuthenticationFlow(): Promise<AuthenticationToken>;
|
|
112
|
-
/**
|
|
113
|
-
* Subscribe and wait for the authentication token.
|
|
114
|
-
*
|
|
115
|
-
* @param requestId - The authentication request ID
|
|
116
|
-
* @returns The authentication token once the user authorizes
|
|
117
|
-
* @throws {AuthenticationError} If subscription fails or returns an error
|
|
118
|
-
*/
|
|
119
121
|
private waitForToken;
|
|
120
122
|
/**
|
|
121
123
|
* Refresh an access token using a refresh token.
|
|
122
124
|
*
|
|
123
125
|
* @param refreshToken - The refresh token from a previous authentication
|
|
124
126
|
* @returns New authentication token with updated access and refresh tokens
|
|
125
|
-
* @throws {
|
|
127
|
+
* @throws {InstanceError} If the refresh fails
|
|
126
128
|
*/
|
|
127
129
|
refreshToken(refreshToken: string): Promise<AuthenticationToken>;
|
|
128
130
|
}
|
|
@@ -135,36 +137,37 @@ declare class AuthenticationError extends Error {
|
|
|
135
137
|
constructor(message: string);
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
138
|
-
* Error thrown
|
|
140
|
+
* Error thrown for errors coming from the Caido cloud API.
|
|
141
|
+
* Used for device approval and device information operations.
|
|
139
142
|
*/
|
|
140
|
-
declare class
|
|
141
|
-
/** Error code from the API */
|
|
142
|
-
readonly code: string;
|
|
143
|
-
constructor(code: string, message: string);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Error thrown when token refresh fails.
|
|
147
|
-
*/
|
|
148
|
-
declare class TokenRefreshError extends AuthenticationError {
|
|
149
|
-
/** Error code from the API */
|
|
150
|
-
readonly code: string;
|
|
151
|
-
constructor(code: string, message: string);
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Error thrown when device approval fails.
|
|
155
|
-
*/
|
|
156
|
-
declare class DeviceApprovalError extends AuthenticationError {
|
|
143
|
+
declare class CloudError extends AuthenticationError {
|
|
157
144
|
/** HTTP status code if available */
|
|
158
145
|
readonly statusCode: number | undefined;
|
|
159
|
-
|
|
146
|
+
/** Error code from the API if available */
|
|
147
|
+
readonly code: string | undefined;
|
|
148
|
+
/** Reason for the error if available */
|
|
149
|
+
readonly reason: string | undefined;
|
|
150
|
+
constructor(message: string, options?: {
|
|
151
|
+
statusCode?: number;
|
|
152
|
+
code?: string;
|
|
153
|
+
reason?: string;
|
|
154
|
+
});
|
|
160
155
|
}
|
|
161
156
|
/**
|
|
162
|
-
* Error thrown
|
|
157
|
+
* Error thrown for errors coming from the Caido instance.
|
|
158
|
+
* Used for authentication flow and token refresh operations.
|
|
163
159
|
*/
|
|
164
|
-
declare class
|
|
165
|
-
/**
|
|
166
|
-
readonly
|
|
167
|
-
|
|
160
|
+
declare class InstanceError extends AuthenticationError {
|
|
161
|
+
/** Error code from the API */
|
|
162
|
+
readonly code: string;
|
|
163
|
+
/** Reason for the error if available */
|
|
164
|
+
readonly reason: string | undefined;
|
|
165
|
+
/** Error message if available */
|
|
166
|
+
readonly errorMessage: string | undefined;
|
|
167
|
+
constructor(code: string, options?: {
|
|
168
|
+
reason?: string;
|
|
169
|
+
message?: string;
|
|
170
|
+
});
|
|
168
171
|
}
|
|
169
172
|
//#endregion
|
|
170
173
|
//#region src/approvers/browser.d.ts
|
|
@@ -213,6 +216,10 @@ interface PATApproverOptions {
|
|
|
213
216
|
allowedScopes?: string[];
|
|
214
217
|
/** The API URL to use. Defaults to "https://api.caido.io" */
|
|
215
218
|
apiUrl?: string;
|
|
219
|
+
/** Request timeout in milliseconds */
|
|
220
|
+
timeout?: number;
|
|
221
|
+
/** Custom fetch implementation */
|
|
222
|
+
fetch?: typeof globalThis.fetch;
|
|
216
223
|
}
|
|
217
224
|
/**
|
|
218
225
|
* PAT-based approver that automatically approves device code requests.
|
|
@@ -234,11 +241,8 @@ declare class PATApprover implements AuthApprover {
|
|
|
234
241
|
private readonly pat;
|
|
235
242
|
private readonly allowedScopes;
|
|
236
243
|
private readonly apiUrl;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
*
|
|
240
|
-
* @param options - Configuration options for the approver
|
|
241
|
-
*/
|
|
244
|
+
private readonly fetchFn;
|
|
245
|
+
private readonly timeout;
|
|
242
246
|
constructor(options: PATApproverOptions);
|
|
243
247
|
/**
|
|
244
248
|
* Approve the authentication request using the PAT.
|
|
@@ -247,27 +251,14 @@ declare class PATApprover implements AuthApprover {
|
|
|
247
251
|
* and finally approves the device.
|
|
248
252
|
*
|
|
249
253
|
* @param request - The authentication request
|
|
250
|
-
* @throws {
|
|
251
|
-
* @throws {DeviceApprovalError} If approving the device fails
|
|
254
|
+
* @throws {CloudError} If fetching device information or approving the device fails
|
|
252
255
|
*/
|
|
253
256
|
approve(request: AuthenticationRequest): Promise<void>;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
*
|
|
257
|
-
* @param userCode - The user code from the authentication request
|
|
258
|
-
* @returns The device information including available scopes
|
|
259
|
-
* @throws {DeviceInformationError} If the request fails
|
|
260
|
-
*/
|
|
257
|
+
private sendRequest;
|
|
258
|
+
private parseOAuth2Error;
|
|
261
259
|
private getDeviceInformation;
|
|
262
|
-
/**
|
|
263
|
-
* Approve the device with the specified scopes.
|
|
264
|
-
*
|
|
265
|
-
* @param userCode - The user code from the authentication request
|
|
266
|
-
* @param scopes - The scopes to approve
|
|
267
|
-
* @throws {DeviceApprovalError} If the request fails
|
|
268
|
-
*/
|
|
269
260
|
private approveDevice;
|
|
270
261
|
}
|
|
271
262
|
//#endregion
|
|
272
|
-
export { type AuthApprover,
|
|
263
|
+
export { type AuthApprover, AuthClient, type AuthClientOptions, AuthenticationError, type AuthenticationRequest, type AuthenticationToken, BrowserApprover, CloudError, type DeviceInformation, type DeviceScope, InstanceError, type OnRequestCallback, PATApprover, type PATApproverOptions };
|
|
273
264
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/approvers/types.ts","../src/client.ts","../src/errors.ts","../src/approvers/browser.ts","../src/approvers/pat.ts"],"mappings":";;AAIA;;;UAAiB,qBAAA;;EAEf,EAAA;;EAEA,QAAA;;EAEA,eAAA;EAEW;EAAX,SAAA,EAAW,IAAA;AAAA;;;;UAMI,mBAAA;;EAEf,WAAA;;EAEA,YAAA;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/approvers/types.ts","../src/client.ts","../src/errors.ts","../src/approvers/browser.ts","../src/approvers/pat.ts"],"mappings":";;AAIA;;;UAAiB,qBAAA;;EAEf,EAAA;;EAEA,QAAA;;EAEA,eAAA;EAEW;EAAX,SAAA,EAAW,IAAA;AAAA;;;;UAMI,mBAAA;;EAEf,WAAA;;EAEA,YAAA;EAIA;EAFA,SAAA,EAAW,IAAA;EAQI;EANf,MAAA;AAAA;;AAgBF;;UAViB,WAAA;EAcP;EAZR,IAAA;;EAEA,WAAA;AAAA;;;;UAMe,iBAAA;ECpCjB;EDsCE,QAAA;;EAEA,MAAA,EAAQ,WAAA;AAAA;;;AA1CV;;;;AAAA,UCEiB,YAAA;;;;;;;ADYjB;ECJE,OAAA,CAAQ,OAAA,EAAS,qBAAA,GAAwB,OAAA;AAAA;;;;;;UCW1B,iBAAA;;EAEf,WAAA;;EAEA,QAAA,EAAU,YAAA;;EAEV,OAAA;EFbF;EEeE,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;;;AFD5B;;;;;AAUA;;;;;cEiBa,UAAA;EAAA,iBACM,WAAA;EAAA,iBACA,UAAA;EAAA,iBACA,YAAA;EAAA,iBACA,QAAA;EAAA,iBACA,MAAA;EAAA,iBACA,OAAA;EAAA,iBACA,OAAA;EAEjB,WAAA,CAAY,OAAA,EAAS,iBAAA;EAAA,QAsBb,eAAA;EAAA,QAMA,mBAAA;;;;;;;;;;AAvEV;;;;EAmGE,uBAAA,CAAA,GAAiC,OAAA,CAAQ,mBAAA;EAAA,QA6C3B,YAAA;;;;;;;;EAgEd,YAAA,CAAmB,YAAA,WAAuB,OAAA,CAAQ,mBAAA;AAAA;;;;AFrOpD;;cGDa,mBAAA,SAA4B,KAAA;EACvC,WAAA,CAAY,OAAA;AAAA;;;;;cAUD,UAAA,SAAmB,mBAAA;EHFnB;EAAA,SGIF,UAAA;EHEM;EAAA,SGAN,IAAA;EHME;EAAA,SGJF,MAAA;EAET,WAAA,CACE,OAAA,UACA,OAAA;IACE,UAAA;IACA,IAAA;IACA,MAAA;EAAA;AAAA;AHKN;;;;AAAA,cGUa,aAAA,SAAsB,mBAAA;EHAnC;EAAA,SGEW,IAAA;;WAEA,MAAA;;WAEA,YAAA;EAET,WAAA,CACE,IAAA,UACA,OAAA;IACE,MAAA;IACA,OAAA;EAAA;AAAA;;;;;;;KC9CM,iBAAA,IACV,OAAA,EAAS,qBAAA,KACN,OAAA;;;;;;AJQL;;;;;;;cIMa,eAAA,YAA2B,YAAA;EAAA,iBACrB,SAAA;;;AJOnB;;;EIAE,WAAA,CAAY,SAAA,EAAW,iBAAA;EJIvB;AAMF;;;;;EIAE,OAAA,CAAc,OAAA,EAAS,qBAAA,GAAwB,OAAA;AAAA;;;;;;UCdhC,kBAAA;;EAEf,GAAA;;EAEA,aAAA;;EAEA,MAAA;ELhBF;EKkBE,OAAA;;EAEA,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;ALN5B;;;;;AAUA;;;;;cKea,WAAA,YAAuB,YAAA;EAAA,iBACjB,GAAA;EAAA,iBACA,aAAA;EAAA,iBACA,MAAA;EAAA,iBACA,OAAA;EAAA,iBACA,OAAA;EAEjB,WAAA,CAAY,OAAA,EAAS,kBAAA;EJ1DvB;;;;;;;;;EI2EE,OAAA,CAAc,OAAA,EAAS,qBAAA,GAAwB,OAAA;EAAA,QAgBjC,WAAA;EAAA,QAgBA,gBAAA;EAAA,QAuBA,oBAAA;EAAA,QA+BA,aAAA;AAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -23,6 +23,8 @@ interface AuthenticationToken {
|
|
|
23
23
|
refreshToken: string;
|
|
24
24
|
/** When the access token expires */
|
|
25
25
|
expiresAt: Date;
|
|
26
|
+
/** The scopes granted to this token */
|
|
27
|
+
scopes: string[];
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Scope information returned from device information endpoint.
|
|
@@ -61,40 +63,47 @@ interface AuthApprover {
|
|
|
61
63
|
//#endregion
|
|
62
64
|
//#region src/client.d.ts
|
|
63
65
|
/**
|
|
66
|
+
* Options for configuring the AuthClient.
|
|
67
|
+
*/
|
|
68
|
+
interface AuthClientOptions {
|
|
69
|
+
/** Base URL of the Caido instance (e.g., "http://localhost:8080") */
|
|
70
|
+
instanceUrl: string;
|
|
71
|
+
/** The approver to use for the authentication flow */
|
|
72
|
+
approver: AuthApprover;
|
|
73
|
+
/** Request timeout in milliseconds */
|
|
74
|
+
timeout?: number;
|
|
75
|
+
/** Custom fetch implementation */
|
|
76
|
+
fetch?: typeof globalThis.fetch;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
64
79
|
* Client for authenticating with a Caido instance.
|
|
65
80
|
*
|
|
66
81
|
* @example
|
|
67
82
|
* ```typescript
|
|
68
|
-
* import {
|
|
83
|
+
* import { AuthClient, BrowserApprover } from "@caido/auth";
|
|
69
84
|
*
|
|
70
|
-
* const auth = new
|
|
71
|
-
* "http://localhost:8080",
|
|
72
|
-
* new BrowserApprover((request) => {
|
|
85
|
+
* const auth = new AuthClient({
|
|
86
|
+
* instanceUrl: "http://localhost:8080",
|
|
87
|
+
* approver: new BrowserApprover((request) => {
|
|
73
88
|
* console.log(`Visit ${request.verificationUrl}`);
|
|
74
89
|
* })
|
|
75
|
-
* );
|
|
90
|
+
* });
|
|
76
91
|
*
|
|
77
92
|
* const token = await auth.startAuthenticationFlow();
|
|
78
93
|
* console.log("Access token:", token.accessToken);
|
|
79
94
|
* ```
|
|
80
95
|
*/
|
|
81
|
-
declare class
|
|
96
|
+
declare class AuthClient {
|
|
82
97
|
private readonly instanceUrl;
|
|
83
98
|
private readonly graphqlUrl;
|
|
84
99
|
private readonly websocketUrl;
|
|
85
100
|
private readonly approver;
|
|
86
101
|
private readonly client;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
* @param instanceUrl - Base URL of the Caido instance (e.g., "http://localhost:8080")
|
|
91
|
-
* @param approver - The approver to use for the authentication flow
|
|
92
|
-
*/
|
|
93
|
-
constructor(instanceUrl: string, approver: AuthApprover);
|
|
94
|
-
/**
|
|
95
|
-
* Convert HTTP(S) URL to WS(S) URL for subscriptions.
|
|
96
|
-
*/
|
|
102
|
+
private readonly fetchFn;
|
|
103
|
+
private readonly timeout;
|
|
104
|
+
constructor(options: AuthClientOptions);
|
|
97
105
|
private getWebsocketUrl;
|
|
106
|
+
private extractErrorDetails;
|
|
98
107
|
/**
|
|
99
108
|
* Start the device code authentication flow.
|
|
100
109
|
*
|
|
@@ -105,24 +114,17 @@ declare class CaidoAuth {
|
|
|
105
114
|
* 4. Returns the authentication token once approved
|
|
106
115
|
*
|
|
107
116
|
* @returns The authentication token
|
|
108
|
-
* @throws {
|
|
117
|
+
* @throws {InstanceError} If the flow fails to start
|
|
109
118
|
* @throws {AuthenticationError} If token retrieval fails
|
|
110
119
|
*/
|
|
111
120
|
startAuthenticationFlow(): Promise<AuthenticationToken>;
|
|
112
|
-
/**
|
|
113
|
-
* Subscribe and wait for the authentication token.
|
|
114
|
-
*
|
|
115
|
-
* @param requestId - The authentication request ID
|
|
116
|
-
* @returns The authentication token once the user authorizes
|
|
117
|
-
* @throws {AuthenticationError} If subscription fails or returns an error
|
|
118
|
-
*/
|
|
119
121
|
private waitForToken;
|
|
120
122
|
/**
|
|
121
123
|
* Refresh an access token using a refresh token.
|
|
122
124
|
*
|
|
123
125
|
* @param refreshToken - The refresh token from a previous authentication
|
|
124
126
|
* @returns New authentication token with updated access and refresh tokens
|
|
125
|
-
* @throws {
|
|
127
|
+
* @throws {InstanceError} If the refresh fails
|
|
126
128
|
*/
|
|
127
129
|
refreshToken(refreshToken: string): Promise<AuthenticationToken>;
|
|
128
130
|
}
|
|
@@ -135,36 +137,37 @@ declare class AuthenticationError extends Error {
|
|
|
135
137
|
constructor(message: string);
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
138
|
-
* Error thrown
|
|
140
|
+
* Error thrown for errors coming from the Caido cloud API.
|
|
141
|
+
* Used for device approval and device information operations.
|
|
139
142
|
*/
|
|
140
|
-
declare class
|
|
141
|
-
/** Error code from the API */
|
|
142
|
-
readonly code: string;
|
|
143
|
-
constructor(code: string, message: string);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Error thrown when token refresh fails.
|
|
147
|
-
*/
|
|
148
|
-
declare class TokenRefreshError extends AuthenticationError {
|
|
149
|
-
/** Error code from the API */
|
|
150
|
-
readonly code: string;
|
|
151
|
-
constructor(code: string, message: string);
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Error thrown when device approval fails.
|
|
155
|
-
*/
|
|
156
|
-
declare class DeviceApprovalError extends AuthenticationError {
|
|
143
|
+
declare class CloudError extends AuthenticationError {
|
|
157
144
|
/** HTTP status code if available */
|
|
158
145
|
readonly statusCode: number | undefined;
|
|
159
|
-
|
|
146
|
+
/** Error code from the API if available */
|
|
147
|
+
readonly code: string | undefined;
|
|
148
|
+
/** Reason for the error if available */
|
|
149
|
+
readonly reason: string | undefined;
|
|
150
|
+
constructor(message: string, options?: {
|
|
151
|
+
statusCode?: number;
|
|
152
|
+
code?: string;
|
|
153
|
+
reason?: string;
|
|
154
|
+
});
|
|
160
155
|
}
|
|
161
156
|
/**
|
|
162
|
-
* Error thrown
|
|
157
|
+
* Error thrown for errors coming from the Caido instance.
|
|
158
|
+
* Used for authentication flow and token refresh operations.
|
|
163
159
|
*/
|
|
164
|
-
declare class
|
|
165
|
-
/**
|
|
166
|
-
readonly
|
|
167
|
-
|
|
160
|
+
declare class InstanceError extends AuthenticationError {
|
|
161
|
+
/** Error code from the API */
|
|
162
|
+
readonly code: string;
|
|
163
|
+
/** Reason for the error if available */
|
|
164
|
+
readonly reason: string | undefined;
|
|
165
|
+
/** Error message if available */
|
|
166
|
+
readonly errorMessage: string | undefined;
|
|
167
|
+
constructor(code: string, options?: {
|
|
168
|
+
reason?: string;
|
|
169
|
+
message?: string;
|
|
170
|
+
});
|
|
168
171
|
}
|
|
169
172
|
//#endregion
|
|
170
173
|
//#region src/approvers/browser.d.ts
|
|
@@ -213,6 +216,10 @@ interface PATApproverOptions {
|
|
|
213
216
|
allowedScopes?: string[];
|
|
214
217
|
/** The API URL to use. Defaults to "https://api.caido.io" */
|
|
215
218
|
apiUrl?: string;
|
|
219
|
+
/** Request timeout in milliseconds */
|
|
220
|
+
timeout?: number;
|
|
221
|
+
/** Custom fetch implementation */
|
|
222
|
+
fetch?: typeof globalThis.fetch;
|
|
216
223
|
}
|
|
217
224
|
/**
|
|
218
225
|
* PAT-based approver that automatically approves device code requests.
|
|
@@ -234,11 +241,8 @@ declare class PATApprover implements AuthApprover {
|
|
|
234
241
|
private readonly pat;
|
|
235
242
|
private readonly allowedScopes;
|
|
236
243
|
private readonly apiUrl;
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
*
|
|
240
|
-
* @param options - Configuration options for the approver
|
|
241
|
-
*/
|
|
244
|
+
private readonly fetchFn;
|
|
245
|
+
private readonly timeout;
|
|
242
246
|
constructor(options: PATApproverOptions);
|
|
243
247
|
/**
|
|
244
248
|
* Approve the authentication request using the PAT.
|
|
@@ -247,27 +251,14 @@ declare class PATApprover implements AuthApprover {
|
|
|
247
251
|
* and finally approves the device.
|
|
248
252
|
*
|
|
249
253
|
* @param request - The authentication request
|
|
250
|
-
* @throws {
|
|
251
|
-
* @throws {DeviceApprovalError} If approving the device fails
|
|
254
|
+
* @throws {CloudError} If fetching device information or approving the device fails
|
|
252
255
|
*/
|
|
253
256
|
approve(request: AuthenticationRequest): Promise<void>;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
*
|
|
257
|
-
* @param userCode - The user code from the authentication request
|
|
258
|
-
* @returns The device information including available scopes
|
|
259
|
-
* @throws {DeviceInformationError} If the request fails
|
|
260
|
-
*/
|
|
257
|
+
private sendRequest;
|
|
258
|
+
private parseOAuth2Error;
|
|
261
259
|
private getDeviceInformation;
|
|
262
|
-
/**
|
|
263
|
-
* Approve the device with the specified scopes.
|
|
264
|
-
*
|
|
265
|
-
* @param userCode - The user code from the authentication request
|
|
266
|
-
* @param scopes - The scopes to approve
|
|
267
|
-
* @throws {DeviceApprovalError} If the request fails
|
|
268
|
-
*/
|
|
269
260
|
private approveDevice;
|
|
270
261
|
}
|
|
271
262
|
//#endregion
|
|
272
|
-
export { type AuthApprover,
|
|
263
|
+
export { type AuthApprover, AuthClient, type AuthClientOptions, AuthenticationError, type AuthenticationRequest, type AuthenticationToken, BrowserApprover, CloudError, type DeviceInformation, type DeviceScope, InstanceError, type OnRequestCallback, PATApprover, type PATApproverOptions };
|
|
273
264
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/approvers/types.ts","../src/client.ts","../src/errors.ts","../src/approvers/browser.ts","../src/approvers/pat.ts"],"mappings":";;AAIA;;;UAAiB,qBAAA;;EAEf,EAAA;;EAEA,QAAA;;EAEA,eAAA;EAEW;EAAX,SAAA,EAAW,IAAA;AAAA;;;;UAMI,mBAAA;;EAEf,WAAA;;EAEA,YAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/approvers/types.ts","../src/client.ts","../src/errors.ts","../src/approvers/browser.ts","../src/approvers/pat.ts"],"mappings":";;AAIA;;;UAAiB,qBAAA;;EAEf,EAAA;;EAEA,QAAA;;EAEA,eAAA;EAEW;EAAX,SAAA,EAAW,IAAA;AAAA;;;;UAMI,mBAAA;;EAEf,WAAA;;EAEA,YAAA;EAIA;EAFA,SAAA,EAAW,IAAA;EAQI;EANf,MAAA;AAAA;;AAgBF;;UAViB,WAAA;EAcP;EAZR,IAAA;;EAEA,WAAA;AAAA;;;;UAMe,iBAAA;ECpCjB;EDsCE,QAAA;;EAEA,MAAA,EAAQ,WAAA;AAAA;;;AA1CV;;;;AAAA,UCEiB,YAAA;;;;;;;ADYjB;ECJE,OAAA,CAAQ,OAAA,EAAS,qBAAA,GAAwB,OAAA;AAAA;;;;;;UCW1B,iBAAA;;EAEf,WAAA;;EAEA,QAAA,EAAU,YAAA;;EAEV,OAAA;EFbF;EEeE,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;;;AFD5B;;;;;AAUA;;;;;cEiBa,UAAA;EAAA,iBACM,WAAA;EAAA,iBACA,UAAA;EAAA,iBACA,YAAA;EAAA,iBACA,QAAA;EAAA,iBACA,MAAA;EAAA,iBACA,OAAA;EAAA,iBACA,OAAA;EAEjB,WAAA,CAAY,OAAA,EAAS,iBAAA;EAAA,QAsBb,eAAA;EAAA,QAMA,mBAAA;;;;;;;;;;AAvEV;;;;EAmGE,uBAAA,CAAA,GAAiC,OAAA,CAAQ,mBAAA;EAAA,QA6C3B,YAAA;;;;;;;;EAgEd,YAAA,CAAmB,YAAA,WAAuB,OAAA,CAAQ,mBAAA;AAAA;;;;AFrOpD;;cGDa,mBAAA,SAA4B,KAAA;EACvC,WAAA,CAAY,OAAA;AAAA;;;;;cAUD,UAAA,SAAmB,mBAAA;EHFnB;EAAA,SGIF,UAAA;EHEM;EAAA,SGAN,IAAA;EHME;EAAA,SGJF,MAAA;EAET,WAAA,CACE,OAAA,UACA,OAAA;IACE,UAAA;IACA,IAAA;IACA,MAAA;EAAA;AAAA;AHKN;;;;AAAA,cGUa,aAAA,SAAsB,mBAAA;EHAnC;EAAA,SGEW,IAAA;;WAEA,MAAA;;WAEA,YAAA;EAET,WAAA,CACE,IAAA,UACA,OAAA;IACE,MAAA;IACA,OAAA;EAAA;AAAA;;;;;;;KC9CM,iBAAA,IACV,OAAA,EAAS,qBAAA,KACN,OAAA;;;;;;AJQL;;;;;;;cIMa,eAAA,YAA2B,YAAA;EAAA,iBACrB,SAAA;;;AJOnB;;;EIAE,WAAA,CAAY,SAAA,EAAW,iBAAA;EJIvB;AAMF;;;;;EIAE,OAAA,CAAc,OAAA,EAAS,qBAAA,GAAwB,OAAA;AAAA;;;;;;UCdhC,kBAAA;;EAEf,GAAA;;EAEA,aAAA;;EAEA,MAAA;ELhBF;EKkBE,OAAA;;EAEA,KAAA,UAAe,UAAA,CAAW,KAAA;AAAA;;;;;;;ALN5B;;;;;AAUA;;;;;cKea,WAAA,YAAuB,YAAA;EAAA,iBACjB,GAAA;EAAA,iBACA,aAAA;EAAA,iBACA,MAAA;EAAA,iBACA,OAAA;EAAA,iBACA,OAAA;EAEjB,WAAA,CAAY,OAAA,EAAS,kBAAA;EJ1DvB;;;;;;;;;EI2EE,OAAA,CAAc,OAAA,EAAS,qBAAA,GAAwB,OAAA;EAAA,QAgBjC,WAAA;EAAA,QAgBA,gBAAA;EAAA,QAuBA,oBAAA;EAAA,QA+BA,aAAA;AAAA"}
|