// OAuth callback страница для обработки авторизации import { useEffect } from "react" export default function OAuthCallback() { useEffect(() => { const handleOAuthCallback = async () => { try { const urlParams = new URLSearchParams(window.location.search) const code = urlParams.get("code") const state = urlParams.get("state") const error = urlParams.get("error") if (error) { // Отправляем ошибку в родительское окно window.opener?.postMessage( { type: "oauth_error", error: error, }, window.location.origin, ) window.close() return } if (!code || !state) { throw new Error("Missing authorization code or state") } // Извлекаем network из state const [network] = state.split("_") // Обмениваем код на токен const token = await exchangeCodeForToken(network, code) if (token) { // Отправляем токен в родительское окно window.opener?.postMessage( { type: "oauth_success", token: token, }, window.location.origin, ) } else { throw new Error("Failed to exchange code for token") } window.close() } catch (error) { console.error("OAuth callback error:", error) window.opener?.postMessage( { type: "oauth_error", error: error instanceof Error ? error.message : "Unknown error", }, window.location.origin, ) window.close() } } // Запускаем обработку после загрузки страницы if (typeof window !== "undefined") { void handleOAuthCallback() } }, []) return (

Completing authorization...

Please wait while we complete the authorization process.

) } async function exchangeCodeForToken(network: string, code: string): Promise { try { switch (network) { case "youtube": return await exchangeYouTubeCode(code) case "tiktok": return await exchangeTikTokCode(code) default: throw new Error(`Token exchange not implemented for ${network}`) } } catch (error) { console.error(`Token exchange failed for ${network}:`, error) throw error } } async function exchangeYouTubeCode(code: string): Promise { const response = await fetch("https://oauth2.googleapis.com/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ client_id: process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_ID || "", client_secret: process.env.NEXT_PUBLIC_YOUTUBE_CLIENT_SECRET || "", code: code, grant_type: "authorization_code", redirect_uri: process.env.NEXT_PUBLIC_OAUTH_REDIRECT_URI || "http://localhost:3000/oauth/callback", }), }) if (!response.ok) { const errorData = await response.json() throw new Error(`YouTube token exchange failed: ${errorData.error_description || "Unknown error"}`) } const data = await response.json() return { accessToken: data.access_token, refreshToken: data.refresh_token, expiresIn: data.expires_in, tokenType: data.token_type, } } async function exchangeTikTokCode(code: string): Promise { const response = await fetch("https://open-api.tiktok.com/oauth/access_token/", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ client_key: process.env.NEXT_PUBLIC_TIKTOK_CLIENT_ID || "", client_secret: process.env.NEXT_PUBLIC_TIKTOK_CLIENT_SECRET || "", code: code, grant_type: "authorization_code", redirect_uri: process.env.NEXT_PUBLIC_OAUTH_REDIRECT_URI || "http://localhost:3000/oauth/callback", }), }) if (!response.ok) { const errorData = await response.json() throw new Error(`TikTok token exchange failed: ${errorData.error_description || "Unknown error"}`) } const data = await response.json() if (data.error) { throw new Error(`TikTok token exchange failed: ${data.error_description || data.error}`) } return { accessToken: data.data.access_token, refreshToken: data.data.refresh_token, expiresIn: data.data.expires_in, tokenType: "Bearer", } }