fix: persistent token cache in get-token.ps1
- Fast path: reads from ~/.ka-note/token.txt if not expired (no MSAL needed) - On expiry: MSAL silent refresh with login hint - Fallback: interactive browser login (~once per 90 days) - Auto-saves every acquired token back to cache file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dc52f64ed4
commit
c28bd34a1a
|
|
@ -1,11 +1,10 @@
|
||||||
<#
|
<#
|
||||||
.SYNOPSIS
|
.SYNOPSIS
|
||||||
Gets a valid Bearer token for the Ka-Note production API via MSAL.PS.
|
Gets a valid Bearer token for the Ka-Note production API.
|
||||||
On first run (or after token cache expires): opens browser popup for login.
|
- Reads from ~/.ka-note/token.txt if not expired (fast path)
|
||||||
Subsequent runs: silent refresh via cached refresh token.
|
- On expiry: MSAL silent refresh (no browser needed if refresh token valid)
|
||||||
|
- Fallback: interactive browser login (once per ~90 days)
|
||||||
.OUTPUTS
|
- Saves every acquired token back to the cache file automatically
|
||||||
Writes the access token string to stdout.
|
|
||||||
#>
|
#>
|
||||||
param()
|
param()
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
@ -13,22 +12,57 @@ $ErrorActionPreference = 'Stop'
|
||||||
$ClientId = '1aba7af7-eec1-4e49-b87e-9f941c0e8630'
|
$ClientId = '1aba7af7-eec1-4e49-b87e-9f941c0e8630'
|
||||||
$TenantId = '94cf90d7-e9ff-49a1-bc3b-a5b94d3cc8ca'
|
$TenantId = '94cf90d7-e9ff-49a1-bc3b-a5b94d3cc8ca'
|
||||||
$Scopes = "api://$ClientId/access"
|
$Scopes = "api://$ClientId/access"
|
||||||
|
$CacheFile = Join-Path $env:USERPROFILE '.ka-note\token.txt'
|
||||||
|
$LoginHint = 'C.KAUER@KRAH-GRUPPE.DE'
|
||||||
|
|
||||||
if (-not (Get-Module -ListAvailable -Name 'MSAL.PS')) {
|
function Get-JwtExpiry([string]$jwt) {
|
||||||
Write-Host " [INFO] Installing MSAL.PS..." -ForegroundColor DarkGray
|
try {
|
||||||
Install-Module -Name 'MSAL.PS' -Scope CurrentUser -Force -AllowClobber
|
$seg = $jwt.Split('.')[1]
|
||||||
|
$pad = 4 - ($seg.Length % 4); if ($pad -ne 4) { $seg += '=' * $pad }
|
||||||
|
$seg = $seg.Replace('-','+').Replace('_','/')
|
||||||
|
$c = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($seg)) | ConvertFrom-Json
|
||||||
|
return [System.DateTimeOffset]::FromUnixTimeSeconds($c.exp).UtcDateTime
|
||||||
|
} catch { return [DateTime]::MinValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Save-Token([string]$token) {
|
||||||
|
$dir = Split-Path $CacheFile
|
||||||
|
if (-not (Test-Path $dir)) { New-Item -ItemType Directory $dir | Out-Null }
|
||||||
|
$token | Set-Content $CacheFile -Encoding UTF8 -NoNewline
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── 1. Try cached file ────────────────────────────────────────────────────────
|
||||||
|
if (Test-Path $CacheFile) {
|
||||||
|
$cached = (Get-Content $CacheFile -Raw -Encoding UTF8).Trim()
|
||||||
|
$exp = Get-JwtExpiry $cached
|
||||||
|
$remaining = ($exp - [DateTime]::UtcNow).TotalMinutes
|
||||||
|
if ($remaining -gt 2) {
|
||||||
|
Write-Host " Token valid for $([math]::Round($remaining)) min (cached)." -ForegroundColor DarkGray
|
||||||
|
Write-Output $cached
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Write-Host " Cached token expired. Refreshing via MSAL..." -ForegroundColor DarkGray
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── 2. MSAL refresh / interactive ────────────────────────────────────────────
|
||||||
|
if (-not (Get-Module -ListAvailable MSAL.PS)) {
|
||||||
|
Write-Host " Installing MSAL.PS..." -ForegroundColor DarkGray
|
||||||
|
Install-Module -Name MSAL.PS -Scope CurrentUser -Force -AllowClobber
|
||||||
}
|
}
|
||||||
Import-Module MSAL.PS -ErrorAction Stop
|
Import-Module MSAL.PS -ErrorAction Stop
|
||||||
|
|
||||||
$p = @{ ClientId = $ClientId; TenantId = $TenantId; Scopes = $Scopes }
|
$p = @{ ClientId = $ClientId; TenantId = $TenantId; Scopes = $Scopes }
|
||||||
|
|
||||||
$r = $null
|
$r = $null
|
||||||
try { $r = Get-MsalToken @p -Silent 2>$null } catch {}
|
try { $r = Get-MsalToken @p -Silent -LoginHint $LoginHint 2>$null } catch {}
|
||||||
|
|
||||||
if (-not $r) {
|
if (-not $r -or -not $r.AccessToken) {
|
||||||
Write-Host " [AUTH] Opening browser for login..." -ForegroundColor Yellow
|
Write-Host " [AUTH] Opening browser for login..." -ForegroundColor Yellow
|
||||||
$r = Get-MsalToken @p -Interactive
|
$r = Get-MsalToken @p -Interactive -LoginHint $LoginHint
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-not $r?.AccessToken) { Write-Error "Failed to acquire token."; exit 1 }
|
if (-not $r -or -not $r.AccessToken) { Write-Error "Failed to acquire token."; exit 1 }
|
||||||
|
|
||||||
|
Save-Token $r.AccessToken
|
||||||
|
Write-Host " Token acquired and cached." -ForegroundColor Green
|
||||||
Write-Output $r.AccessToken
|
Write-Output $r.AccessToken
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue