When building integrations that sit behind an AWS IAM Identity Center (formerly AWS SSO) authentication gateway, you often need a raw access token to authorize requests. While the AWS CLI handles interactive logins smoothly, extracting that token programmatically for downstream scripts or API clients can be tricky—especially when balancing interactive sessions with silent, background processes.
Here is a robust PowerShell solution that extracts the active AWS SSO access token directly from the CLI cache, conditionally triggers browser logins based on the execution context, and outputs the token in a clean JSON format.
The PowerShell Script
This script reads the local AWS SSO cache, validates the token’s expiration, and handles interactive logins gracefully.
# Emits {"token": "..."} on stdout for Cowork 3P gateway auth.
# Uses the IAM Identity Center access token from the AWS CLI SSO cache.
$ErrorActionPreference = 'Stop'
$ProfileName = 'cowork' # your AWS SSO profile
$SsoCache = Join-Path $env:USERPROFILE '.aws\sso\cache'
$Ctx = $env:CLAUDE_HELPER_CONTEXT # session-start | refresh | health-check
function Get-CachedSsoToken {
if (-not (Test-Path $SsoCache)) { return $null }
Get-ChildItem $SsoCache -Filter *.json |
Sort-Object LastWriteTime -Descending |
ForEach-Object {
try { Get-Content $_.FullName -Raw | ConvertFrom-Json } catch { $null }
} |
Where-Object {
$_.accessToken -and $_.expiresAt -and
([datetime]$_.expiresAt).ToUniversalTime() -gt (Get-Date).ToUniversalTime().AddMinutes(5)
} |
Select-Object -First 1
}
$tok = Get-CachedSsoToken
# No valid cached token: only trigger interactive browser login when this is
# a user-initiated session start, never during silent mid-session refresh
# or background health checks (those must run non-interactively).
if (-not $tok) {
if ($Ctx -and $Ctx -ne 'session-start') {
Write-Error "SSO token expired and context '$Ctx' is non-interactive. Run 'aws sso login --profile $ProfileName'."
exit 1
}
& aws sso login --profile $ProfileName | Out-Null
if ($LASTEXITCODE -ne 0) { Write-Error "aws sso login failed"; exit 1 }
$tok = Get-CachedSsoToken
if (-not $tok) { Write-Error "No SSO token found after login"; exit 1 }
}
# stdout contract: bare token or JSON {"token": ..., "headers": {...}}
@{ token = $tok.accessToken } | ConvertTo-Json -CompressHow It Works
1. Smart Cache Extraction
Rather than forcing a login every time the script runs, the Get-CachedSsoToken function parses the local AWS CLI cache directory (~/.aws/sso/cache). It iterates through the JSON payload of recent sessions, ensuring two things:
- An
accessTokenactually exists in the file. - The token has at least 5 minutes of validity remaining before it expires (
$_.expiresAt).
If a valid token is found, the script skips the login process entirely, saving time and preventing unnecessary browser popups.
2. Context-Aware Execution
Background processes and interactive terminals require different handling. If a token is expired, the script checks the $env:CLAUDE_HELPER_CONTEXT environment variable:
- Interactive (
session-start): If the user is actively initiating a session, the script triggersaws sso loginto open a browser window for re-authentication. - Non-Interactive (
refreshorhealth-check): If the script is running silently in the background, a browser popup would interrupt the user or hang the process indefinitely. In this state, it fails gracefully with an actionable error message, prompting the user to manually authenticate later.
3. Clean JSON Output Contract
Many third-party gateways and API clients expect a structured response. By compressing a hashtable into JSON (@{ token = $tok.accessToken } | ConvertTo-Json -Compress), the script outputs a strict {"token": "..."} format via stdout, making it effortlessly readable by Node.js, Python, or standard CI/CD pipelines.
# Emits {"token": "..."} on stdout for Cowork 3P gateway auth.
# Uses the IAM Identity Center access token from the AWS CLI SSO cache.
$ErrorActionPreference = 'Stop'
$ProfileName = 'cowork' # your AWS SSO profile
$SsoCache = Join-Path $env:USERPROFILE '.aws\sso\cache'
$Ctx = $env:CLAUDE_HELPER_CONTEXT # session-start | refresh | health-check
function Get-CachedSsoToken {
if (-not (Test-Path $SsoCache)) { return $null }
Get-ChildItem $SsoCache -Filter *.json |
Sort-Object LastWriteTime -Descending |
ForEach-Object {
try { Get-Content $_.FullName -Raw | ConvertFrom-Json } catch { $null }
} |
Where-Object {
$_.accessToken -and $_.expiresAt -and
([datetime]$_.expiresAt).ToUniversalTime() -gt (Get-Date).ToUniversalTime().AddMinutes(5)
} |
Select-Object -First 1
}
$tok = Get-CachedSsoToken
# No valid cached token: only trigger interactive browser login when this is
# a user-initiated session start, never during silent mid-session refresh
# or background health checks (those must run non-interactively).
if (-not $tok) {
if ($Ctx -and $Ctx -ne 'session-start') {
Write-Error "SSO token expired and context '$Ctx' is non-interactive. Run 'aws sso login --profile $ProfileName'."
exit 1
}
& aws sso login --profile $ProfileName | Out-Null
if ($LASTEXITCODE -ne 0) { Write-Error "aws sso login failed"; exit 1 }
$tok = Get-CachedSsoToken
if (-not $tok) { Write-Error "No SSO token found after login"; exit 1 }
}
# stdout contract: bare token or JSON {"token": ..., "headers": {...}}
@{ token = $tok.accessToken } | ConvertTo-Json -Compress