@assistant-ui/react
Version:
Typescript/React library for AI Chat
1 lines • 8.66 kB
Source Map (JSON)
{"version":3,"sources":["../../src/cloud/AssistantCloudAuthStrategy.tsx"],"sourcesContent":["export type AssistantCloudAuthStrategy = {\n readonly strategy: \"anon\" | \"jwt\" | \"api-key\";\n getAuthHeaders(): Promise<Record<string, string> | false>;\n readAuthHeaders(headers: Headers): void;\n};\n\nconst getJwtExpiry = (jwt: string): number => {\n try {\n const parts = jwt.split(\".\");\n const bodyPart = parts[1];\n if (!bodyPart) {\n throw new Error(\"Invalid JWT format\");\n }\n\n // Convert from Base64Url to Base64 and add padding if necessary\n let base64 = bodyPart.replace(/-/g, \"+\").replace(/_/g, \"/\");\n while (base64.length % 4 !== 0) {\n base64 += \"=\";\n }\n\n // Decode the Base64 string and parse the payload\n const payload = atob(base64);\n const payloadObj = JSON.parse(payload);\n const exp = payloadObj.exp;\n\n if (!exp || typeof exp !== \"number\") {\n throw new Error('JWT does not contain a valid \"exp\" field');\n }\n\n // Convert expiration time to milliseconds\n return exp * 1000;\n } catch (error) {\n throw new Error(\"Unable to determine the token expiry: \" + error);\n }\n};\n\nexport class AssistantCloudJWTAuthStrategy\n implements AssistantCloudAuthStrategy\n{\n public readonly strategy = \"jwt\";\n\n private cachedToken: string | null = null;\n private tokenExpiry: number | null = null;\n #authTokenCallback: () => Promise<string | null>;\n\n constructor(authTokenCallback: () => Promise<string | null>) {\n this.#authTokenCallback = authTokenCallback;\n }\n\n public async getAuthHeaders(): Promise<Record<string, string> | false> {\n const currentTime = Date.now();\n\n // Use cached token if it's valid for at least 30 more seconds\n if (\n this.cachedToken &&\n this.tokenExpiry &&\n this.tokenExpiry - currentTime > 30 * 1000\n ) {\n return { Authorization: `Bearer ${this.cachedToken}` };\n }\n\n // Fetch a new token via the callback\n const newToken = await this.#authTokenCallback();\n if (!newToken) return false;\n\n this.cachedToken = newToken;\n this.tokenExpiry = getJwtExpiry(newToken);\n\n return { Authorization: `Bearer ${newToken}` };\n }\n\n public readAuthHeaders(headers: Headers) {\n const authHeader = headers.get(\"Authorization\");\n if (!authHeader) return;\n\n const [scheme, token] = authHeader.split(\" \");\n if (scheme !== \"Bearer\" || !token) {\n throw new Error(\"Invalid auth header received\");\n }\n\n this.cachedToken = token;\n this.tokenExpiry = getJwtExpiry(token);\n }\n}\n\nexport class AssistantCloudAPIKeyAuthStrategy\n implements AssistantCloudAuthStrategy\n{\n public readonly strategy = \"api-key\";\n\n #apiKey: string;\n #userId: string;\n #workspaceId: string;\n\n constructor(apiKey: string, userId: string, workspaceId: string) {\n this.#apiKey = apiKey;\n this.#userId = userId;\n this.#workspaceId = workspaceId;\n }\n\n public async getAuthHeaders(): Promise<Record<string, string>> {\n return {\n Authorization: `Bearer ${this.#apiKey}`,\n \"Aui-User-Id\": this.#userId,\n \"Aui-Workspace-Id\": this.#workspaceId,\n };\n }\n\n public readAuthHeaders() {\n // No operation needed for API key auth\n }\n}\n\nconst AUI_REFRESH_TOKEN_NAME = \"aui:refresh_token\";\n\nexport class AssistantCloudAnonymousAuthStrategy\n implements AssistantCloudAuthStrategy\n{\n public readonly strategy = \"anon\";\n\n private baseUrl: string;\n private jwtStrategy: AssistantCloudJWTAuthStrategy;\n\n constructor(baseUrl: string) {\n this.baseUrl = baseUrl;\n this.jwtStrategy = new AssistantCloudJWTAuthStrategy(async () => {\n const currentTime = Date.now();\n const storedRefreshTokenJson = localStorage.getItem(\n AUI_REFRESH_TOKEN_NAME,\n );\n const storedRefreshToken = storedRefreshTokenJson\n ? (JSON.parse(storedRefreshTokenJson) as {\n token: string;\n expires_at: string;\n })\n : undefined;\n\n if (storedRefreshToken) {\n const refreshExpiry = new Date(storedRefreshToken.expires_at).getTime();\n if (refreshExpiry - currentTime > 30 * 1000) {\n const response = await fetch(\n `${this.baseUrl}/v1/auth/tokens/refresh`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ refresh_token: storedRefreshToken.token }),\n },\n );\n\n if (response.ok) {\n const data = await response.json();\n const { access_token, refresh_token } = data;\n if (refresh_token) {\n localStorage.setItem(\n AUI_REFRESH_TOKEN_NAME,\n JSON.stringify(refresh_token),\n );\n }\n return access_token;\n }\n } else {\n localStorage.removeItem(AUI_REFRESH_TOKEN_NAME);\n }\n }\n\n // No valid refresh token; request a new anonymous token\n const response = await fetch(`${this.baseUrl}/v1/auth/tokens/anonymous`, {\n method: \"POST\",\n });\n\n if (!response.ok) return null;\n\n const data = await response.json();\n const { access_token, refresh_token } = data;\n\n if (!access_token || !refresh_token) return null;\n\n localStorage.setItem(\n AUI_REFRESH_TOKEN_NAME,\n JSON.stringify(refresh_token),\n );\n return access_token;\n });\n }\n\n public async getAuthHeaders(): Promise<Record<string, string> | false> {\n return this.jwtStrategy.getAuthHeaders();\n }\n\n public readAuthHeaders(headers: Headers): void {\n this.jwtStrategy.readAuthHeaders(headers);\n }\n}\n"],"mappings":"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","names":["response","data","access_token","refresh_token"]}