import { defineEventHandler, createError } from 'h3' import type LogtoClient from '@logto/node' const RESOURCES = { teams: 'https://teams.optovia.ru', exchange: 'https://exchange.optovia.ru', orders: 'https://orders.optovia.ru', kyc: 'https://kyc.optovia.ru', billing: 'https://billing.optovia.ru' } as const export type ResourceKey = keyof typeof RESOURCES export interface TokenInfo { token: string expiresAt: number } export interface RefreshResponse { tokens: Partial> } function decodeTokenExpiry(token: string): number { try { const payload = token.split('.')[1] if (payload) { const decoded = JSON.parse(Buffer.from(payload, 'base64').toString('utf8')) if (decoded.exp) { return decoded.exp * 1000 } } } catch { // ignore } return Date.now() + 3600 * 1000 // default 1 hour } /** * Refresh all access tokens for all resources. * Gets organizationId from logtoUser (first organization). * Returns tokens with expiry timestamps. */ export default defineEventHandler(async (event): Promise => { const client = event.context.logtoClient as LogtoClient | undefined const logtoUser = event.context.logtoUser as { organizations?: string[] } | undefined if (!client) { throw createError({ statusCode: 401, message: 'Not authenticated' }) } // Get first organization from Logto user const organizationId = logtoUser?.organizations?.[0] const tokens: Partial> = {} // Fetch all tokens in parallel with organization context await Promise.all( (Object.entries(RESOURCES) as [ResourceKey, string][]).map(async ([key, resource]) => { try { const token = await client.getAccessToken(resource, organizationId) if (token) { tokens[key] = { token, expiresAt: decodeTokenExpiry(token) } } } catch { // Token not available for this resource, skip } }) ) return { tokens } })