UNPKG

authvisage-sdk

Version:
102 lines 4.01 kB
import { OAuthStateHandler } from "@/helpers/oauthStateHandler"; import { PKCEHandler } from "@/helpers/pkceHandler"; import { clientOptionsSchema, } from "@/schemas/clientOptions"; import { safeAwait } from "@/utils/safe-await"; import { TokenManager } from "@/auth/tokenManager"; /** * Main AuthVisage client for handling authentication */ export class AuthVisageClient { constructor(options) { const { platformUrl, projectId, backendUrl, redirectUrl } = options; const { error } = clientOptionsSchema.safeParse(options); if (error) { const message = error.issues[0].message; throw new Error(`Invalid client options: ${message} (path: ${error.issues[0].path.join(".")})`); } this.projectId = projectId; this.platformUrl = platformUrl; this.backendUrl = backendUrl; this.redirectUrl = redirectUrl; this.auth = new TokenManager(backendUrl); this._handleOAuthCallback().catch(console.error); } /** * Get Session id from the backend * @returns Session id */ async _getSessionId() { const response = await fetch(`${this.backendUrl}/create-session`); if (!response.ok) { throw new Error("Session retrieval failed." + response.statusText); } const [data, error] = await safeAwait(response.json()); if (error) { throw new Error("Failed to parse session ID response."); } return data.id; } /** * Constructs the OAuth authorization URL */ async _constructAuthUrl() { const state = OAuthStateHandler.generate(); const pkcePair = await PKCEHandler.generate(); const sessionId = await this._getSessionId(); const url = new URL(this.platformUrl + "/authorize"); url.searchParams.append("state", state); url.searchParams.append("projectId", this.projectId); url.searchParams.append("redirect_uri", this.redirectUrl); url.searchParams.append("code_challenge", pkcePair.codeChallenge); url.searchParams.append("code_challenge_method", "S256"); url.searchParams.append("session_id", sessionId); return url.toString(); } /** * Handles the OAuth callback and exchanges the authorization code for an access token */ async _handleOAuthCallback() { const urlParams = new URLSearchParams(window.location.search); const code = urlParams.get("code"); const returnedState = urlParams.get("state"); const codeVerifier = PKCEHandler.getCodeVerifier(); if (!code || !returnedState) { throw new Error("Missing authorization code or state in the URL parameters."); } if (!OAuthStateHandler.validate(returnedState)) { throw new Error("State validation failed! Possible CSRF attack."); } const response = await fetch(`${this.backendUrl}/token`, { method: "POST", body: JSON.stringify({ code, code_verifier: codeVerifier, }), }); if (!response.ok) { throw new Error(`Token exchange failed: ${response.statusText}`); } const [data, error] = await safeAwait(response.json()); if (error) { throw new Error("Failed to parse token response."); } if (!data.access_token) { throw new Error("Token response missing access_token"); } if (data.refresh_token) { this.auth.setSession(data); } return data.access_token; } /** * Initiates the face login process by redirecting the user to AuthVisage */ async faceLogin() { const [data, error] = await safeAwait(this._constructAuthUrl()); if (error) { throw new Error(`Face login failed: ${error.message}`); } window.location.assign(data); } } //# sourceMappingURL=authVisageClient.js.map