<# .SYNOPSIS Stores a Bearer token for Ka-Note prod in %USERPROFILE%\.ka-note\token.txt. Run this after copying a fresh token from the Ka-Note browser app. .PARAMETER Token The JWT token string. If omitted, reads from clipboard. .EXAMPLE .\set-token.ps1 "eyJ..." .\set-token.ps1 # reads from clipboard #> param([string]$Token) $ErrorActionPreference = 'Stop' if (-not $Token) { $Token = Get-Clipboard if (-not $Token) { Write-Error "No token provided and clipboard is empty."; exit 1 } Write-Host " Read token from clipboard." -ForegroundColor DarkGray } $Token = $Token.Trim() if (-not $Token.StartsWith('eyJ')) { Write-Error "Does not look like a JWT token (expected 'eyJ...')." exit 1 } # Parse expiry try { $parts = $Token.Split('.') $payload = $parts[1] $pad = 4 - ($payload.Length % 4); if ($pad -ne 4) { $payload += '=' * $pad } $payload = $payload.Replace('-', '+').Replace('_', '/') $claims = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($payload)) | ConvertFrom-Json $expUtc = [System.DateTimeOffset]::FromUnixTimeSeconds($claims.exp).UtcDateTime $local = $expUtc.ToLocalTime() $remaining = [math]::Round(($expUtc - [System.DateTime]::UtcNow).TotalMinutes) Write-Host " Token expires: $($local.ToString('HH:mm')) ($remaining min remaining)" -ForegroundColor $(if ($remaining -lt 10) { 'Yellow' } else { 'Green' }) } catch { Write-Host " Token stored (could not parse expiry)." -ForegroundColor DarkGray } # Save $dir = Join-Path $env:USERPROFILE '.ka-note' if (-not (Test-Path $dir)) { New-Item -ItemType Directory $dir | Out-Null } $file = Join-Path $dir 'token.txt' $Token | Set-Content $file -Encoding UTF8 -NoNewline Write-Host " Saved to: $file" -ForegroundColor Green