# v6: p l  1 D1 t   pD \ p 1 \D l, \ 8 D. FreeeX OAuth2 **(Rotating)  p** )D i. , \ a8 pD  D L  p \  p, t  p@ 4T).  Tܔ `.env` |X  pD X, \  @  pD X J0 L8 l| ` L || \ xt Di. t 줸 \  @  pD JSON | <\ X, \ X x<\ l<\ `  ܤ\D D1i. ## 1: p 1 < `src/tokenManager.ts` |D 1X  pD X $ 0D li. ```typescript // src/tokenManager.ts import * as fs from 'fs'; import * as path from 'path'; const TOKEN_FILE_PATH = path.join(__dirname, '..', 'tokens.json'); interface TokenData { refresh_token: string; updated_at: string; } export const saveRefreshToken = (refreshToken: string): void => { const tokenData: TokenData = { refresh_token: refreshToken, updated_at: new Date().toISOString() }; try { fs.writeFileSync(TOKEN_FILE_PATH, JSON.stringify(tokenData, null, 2), 'utf-8'); console.log(' \  pD .'); } catch (error) { console.error('L Refresh token (:', error); } }; export const loadRefreshToken = (): string | null => { try { if (!fs.existsSync(TOKEN_FILE_PATH)) { console.log(' pt Ƶ. \ xD ĉi.'); return null; } const data = fs.readFileSync(TOKEN_FILE_PATH, 'utf-8'); const tokenData: TokenData = JSON.parse(data); console.log(`  pD T. ( 1: ${tokenData.updated_at})`); return tokenData.refresh_token; } catch (error) { console.error('L Refresh token \ (:', error); return null; } }; ``` ## 2: Freee t|t p 0 `src/freeeClient.ts` |D X \  pD <\ X] i. ```typescript // src/freeeClient.ts import { saveRefreshToken, loadRefreshToken } from './tokenManager'; // 0t TX FREEE_REFRESH_TOKEN D  let currentRefreshToken = loadRefreshToken() || process.env.FREEE_REFRESH_TOKEN; if (!currentRefreshToken) { throw new Error(' pt Ƶ. || \ \ xt Di.'); } ``` `refreshAccessToken` h| X \  @  pD i: ```typescript const refreshAccessToken = async (): Promise => { try { const response = await axios.post( 'https://accounts.secure.freee.co.jp/public_api/token', new URLSearchParams({ grant_type: 'refresh_token', client_id: FREEE_CLIENT_ID!, client_secret: FREEE_CLIENT_SECRET!, refresh_token: currentRefreshToken!, }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); const newAccessToken = response.data.access_token; const newRefreshToken = response.data.refresh_token; // =% \  pt  t if (newRefreshToken && newRefreshToken !== currentRefreshToken) { saveRefreshToken(newRefreshToken); currentRefreshToken = newRefreshToken; } console.log(' \ a8 pD  X.'); return newAccessToken; } catch (error: any) { console.error('L p 1 (:', error.response?.data || error.message); throw new Error('p 1 (. Freee xt D`  .'); } }; ``` ## 3: `.gitignore` p | `tokens.json` |Д \ x  h\,  Git  J] `.gitignore` i. ``` # .gitignore node_modules/ .env tokens.json dist/ ``` ## 4: ّ Ux t l| Xt: 1. ** **: `tokens.json` |t <\ `.env`X `FREEE_REFRESH_TOKEN` 2. p 1 \  pD `tokens.json` 3. **P t**: `tokens.json`  pD <\ 4 4. || \ x D! ```bash npx ts-node src/index.ts ``` % : ```   pD T. ( 1: 2025-11-27T06:22:23.777Z) a8 pt Ƶ. \  ...  \ a8 pD  X.  \  pD .  11X p D 8T. ``` --- t Freee API xt DX Tȵ! L **v7** 줸 Vertex AI (Gemini)| $X p D <\ XX AI 0D X.