hub-session-refresh.mjs
sha256:4215cecbbabf5591b1ff69053cc938b4b6c800f0d487be40618c1d4254d8b67b
security: npm audit fix pre-bridge 2026-09-05
Human
2 days ago
| 1 | #!/usr/bin/env node |
| 2 | /** |
| 3 | * Refresh hosted Hub human session JWT (operator laptop only). |
| 4 | * |
| 5 | * One-time bootstrap — copy hub_token from Application → Local Storage, then: |
| 6 | * node scripts/hub-session-refresh.mjs --save-access-token '<jwt>' |
| 7 | * Exchanges the access JWT for a durable refresh token via POST /api/v1/auth/establish-refresh |
| 8 | * (requires gateway deploy with establish-refresh route). |
| 9 | * |
| 10 | * Routine use (auto-rotates refresh token, caches access JWT): |
| 11 | * node scripts/hub-session-refresh.mjs |
| 12 | * |
| 13 | * Optional env: |
| 14 | * KNOWTATION_HUB_API=https://api.knowtation.store |
| 15 | * KNOWTATION_HUB_REFRESH_TOKEN_FILE=~/.config/knowtation/hub_refresh |
| 16 | * KNOWTATION_HUB_TOKEN_FILE=~/.config/knowtation/hub_session |
| 17 | * |
| 18 | * Does not print JWTs unless --print-token (local operator only). |
| 19 | */ |
| 20 | |
| 21 | import path from 'node:path'; |
| 22 | import { fileURLToPath } from 'node:url'; |
| 23 | import dotenv from 'dotenv'; |
| 24 | |
| 25 | import { |
| 26 | DEFAULT_REFRESH_FILE, |
| 27 | DEFAULT_SESSION_FILE, |
| 28 | decodeAccessClaims, |
| 29 | ensureHostedSessionAccessToken, |
| 30 | establishHostedRefreshFromAccess, |
| 31 | expandHome, |
| 32 | refreshHostedSessionAccessToken, |
| 33 | writeSecretFile, |
| 34 | } from './lib/hub-session-auth.mjs'; |
| 35 | |
| 36 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 37 | dotenv.config({ path: path.join(__dirname, '..', '.env') }); |
| 38 | |
| 39 | function usage() { |
| 40 | console.log(`Usage: |
| 41 | node scripts/hub-session-refresh.mjs [--force] |
| 42 | node scripts/hub-session-refresh.mjs --save-refresh '<ktn_refresh value>' |
| 43 | node scripts/hub-session-refresh.mjs --save-access-token '<hub_token JWT from Local Storage>' |
| 44 | node scripts/hub-session-refresh.mjs --status |
| 45 | node scripts/hub-session-refresh.mjs --print-token # local only; never commit output |
| 46 | |
| 47 | Stores: |
| 48 | refresh → ${DEFAULT_REFRESH_FILE} |
| 49 | access → ${DEFAULT_SESSION_FILE} |
| 50 | `); |
| 51 | } |
| 52 | |
| 53 | const args = process.argv.slice(2); |
| 54 | if (args.includes('-h') || args.includes('--help')) { |
| 55 | usage(); |
| 56 | process.exit(0); |
| 57 | } |
| 58 | |
| 59 | if (args[0] === '--save-refresh') { |
| 60 | const token = (args[1] || '').trim(); |
| 61 | if (!token || token.includes(' ')) { |
| 62 | console.error('Provide the ktn_refresh cookie value: --save-refresh \'<id>.<secret>\''); |
| 63 | process.exit(2); |
| 64 | } |
| 65 | const refreshFile = expandHome(process.env.KNOWTATION_HUB_REFRESH_TOKEN_FILE || DEFAULT_REFRESH_FILE); |
| 66 | writeSecretFile(refreshFile, token); |
| 67 | console.log(`saved refresh token → ${refreshFile}`); |
| 68 | const result = await refreshHostedSessionAccessToken(); |
| 69 | if (!result.ok) { |
| 70 | console.error(`refresh failed: ${result.code} — ${result.detail}`); |
| 71 | process.exit(1); |
| 72 | } |
| 73 | console.log(`access token cached (${result.claims.type ?? 'session'}, exp in ${result.claims.expiresInSec}s)`); |
| 74 | process.exit(0); |
| 75 | } |
| 76 | |
| 77 | if (args[0] === '--save-access-token') { |
| 78 | const access = (args[1] || '').trim(); |
| 79 | if (!access || access.split('.').length !== 3) { |
| 80 | console.error('Paste hub_token from DevTools → Application → Local Storage → hub_token'); |
| 81 | process.exit(2); |
| 82 | } |
| 83 | const claims = decodeAccessClaims(access); |
| 84 | if (claims.expired) { |
| 85 | console.error('hub_token is expired — sign in again and copy a fresh token'); |
| 86 | process.exit(2); |
| 87 | } |
| 88 | const established = await establishHostedRefreshFromAccess(access); |
| 89 | if (!established.ok) { |
| 90 | console.error(`establish-refresh failed: ${established.code} — ${established.detail}`); |
| 91 | process.exit(1); |
| 92 | } |
| 93 | const refreshFile = expandHome(process.env.KNOWTATION_HUB_REFRESH_TOKEN_FILE || DEFAULT_REFRESH_FILE); |
| 94 | const sessionFile = expandHome(process.env.KNOWTATION_HUB_TOKEN_FILE || DEFAULT_SESSION_FILE); |
| 95 | console.log(`saved refresh token → ${refreshFile}`); |
| 96 | console.log(`saved access JWT → ${sessionFile} (type=${claims.type ?? 'session'}, exp_in_s=${claims.expiresInSec})`); |
| 97 | console.log('auto-refresh enabled — run: node scripts/hub-session-refresh.mjs'); |
| 98 | process.exit(0); |
| 99 | } |
| 100 | |
| 101 | if (args.includes('--status')) { |
| 102 | const fs = await import('node:fs'); |
| 103 | const sessionFile = expandHome(process.env.KNOWTATION_HUB_TOKEN_FILE || DEFAULT_SESSION_FILE); |
| 104 | const refreshFile = expandHome(process.env.KNOWTATION_HUB_REFRESH_TOKEN_FILE || DEFAULT_REFRESH_FILE); |
| 105 | const envTok = (process.env.KNOWTATION_HUB_TOKEN || '').trim(); |
| 106 | console.log(JSON.stringify({ |
| 107 | refresh_file: refreshFile, |
| 108 | refresh_present: fs.existsSync(refreshFile), |
| 109 | session_file: sessionFile, |
| 110 | session_present: fs.existsSync(sessionFile), |
| 111 | env_token_present: Boolean(envTok), |
| 112 | env_token: envTok ? decodeAccessClaims(envTok) : null, |
| 113 | session_file_claims: fs.existsSync(sessionFile) |
| 114 | ? decodeAccessClaims(fs.readFileSync(sessionFile, 'utf8').trim()) |
| 115 | : null, |
| 116 | }, null, 2)); |
| 117 | process.exit(0); |
| 118 | } |
| 119 | |
| 120 | const force = args.includes('--force'); |
| 121 | const result = await ensureHostedSessionAccessToken({ forceRefresh: force }); |
| 122 | if (!result.ok) { |
| 123 | console.error(`FAIL ${result.code}: ${result.detail}`); |
| 124 | process.exit(1); |
| 125 | } |
| 126 | |
| 127 | const claims = decodeAccessClaims(result.accessToken); |
| 128 | console.log(`OK source=${result.source} refreshed=${result.refreshed} type=${claims.type ?? 'session'} exp_in_s=${claims.expiresInSec}`); |
| 129 | |
| 130 | if (args.includes('--print-token')) { |
| 131 | console.log(result.accessToken); |
| 132 | } |
File History
1 commit
sha256:4215cecbbabf5591b1ff69053cc938b4b6c800f0d487be40618c1d4254d8b67b
security: npm audit fix pre-bridge 2026-09-05
Human
2 days ago