Aquire short lived access tokens
Prerequisites
Section titled “Prerequisites”- You have a service account: Create a new service account
- You have a service account key created: Create a new service account key
Procedure
Section titled “Procedure”Use this command if the key pair was generated by STACKIT:
stackit auth activate-service-account --service-account-key-path service-account.json --only-print-access-tokenUse this command, if you created the private key on your own:
stackit auth activate-service-account --service-account-key-path service-account.json --private-key-path key.pem --only-print-access-tokenManual implementation
Section titled “Manual implementation”To manually acquire a short-lived access token, you need to create and sign a JWT first. Thesefields are needed:
Header:
Section titled “Header:”kid: Populate this field by extracting the corresponding key from service-account.jsonalg: Your signature algorithm. We recommend “RS512”typ: “JWT”
Payload:
Section titled “Payload:”iss: Populate this field by extracting the corresponding key from service-account.jsonsub: Populate this field by extracting the corresponding key from service-account.jsonaud: Populate this field by extracting the corresponding key from service-account.jsonjti: Populate this field by generating a uuidv4-stringiat: Populate this field with the present time in epoch time format in your local timeexp: Populate this field with the present time (local time) + 600 seconds in epoch time format
The following bash script implements all those tasks. Please use it as a reference for your manual implementations:
Refer to the Request short lived API token documentation in the API Explorer.
Use the following Bash script to retrieve an access token on Linux or macOS.
Prerequisites
- Bash 4.0 or later
jq,openssl,curl, anduuidgeninstalled- A STACKIT service account with a valid JSON configuration file
Steps to acquire an access token using the Bash script:
-
Download your service account configuration from the STACKIT Portal and save it as
service-account.json. -
Copy the script
get-stackit-access-token.shfrom here. -
Make the script executable:
Terminal window chmod +x get-stackit-access-token.sh -
Run the script:
Terminal window ./get-stackit-access-token.shAlternatively, specify a custom path to the configuration file:
Terminal window ./get-stackit-access-token.sh /path/to/service-account.json -
The script outputs the access token. To use it for API requests:
Terminal window ACCESS_TOKEN=$(./get-stackit-access-token.sh | tail -1)curl -H "Authorization: Bearer $ACCESS_TOKEN" \"https://api.stackit.cloud/v1/..."
Bash Script
Section titled “Bash Script”#!/bin/bash
set -euo pipefail
CONFIG="service-account.json"TOKEN_URL="https://service-account.api.stackit.cloud/token"
# --- Konfiguration aus JSON-Datei lesen ---ISS=$(jq -r '.credentials.iss' "$CONFIG")SUB=$(jq -r '.credentials.sub' "$CONFIG")AUD=$(jq -r '.credentials.aud' "$CONFIG")KID=$(jq -r '.credentials.kid' "$CONFIG")PRIVATE_KEY_RAW=$(jq -r '.credentials.privateKey' "$CONFIG")
# --- Write private key in file ---PRIVATE_KEY_FILE=$(mktemp)echo "$PRIVATE_KEY_RAW" | sed 's/\\n/\n/g' > "$PRIVATE_KEY_FILE"
# --- Timestamp for JWT ---NOW=$(date +%s)EXP=$((NOW + 600)) # Set token validity to ten minutesJTI=$(uuidgen) # Optional in spec but mandatory for STACKIT
# --- JWT header & payload ---HEADER=$(jq -nc --arg kid "$KID" '{alg:"RS512", typ:"JWT", kid:$kid}')PAYLOAD=$(jq -nc \ --arg iss "$ISS" \ --arg sub "$SUB" \ --arg aud "$AUD" \ --arg jti "$JTI" \ --argjson iat "$NOW" \ --argjson exp "$EXP" \ '{iss:$iss, sub:$sub, aud:$aud, iat:$iat, exp:$exp, jti:$jti}')
# --- Base64URL encode function ---b64enc() { openssl base64 -e -A | tr '+/' '-_' | tr -d '='}
# --- Build and sign JWT ---HEADER_B64=$(echo -n "$HEADER" | b64enc)PAYLOAD_B64=$(echo -n "$PAYLOAD" | b64enc)DATA="${HEADER_B64}.${PAYLOAD_B64}"
SIGNATURE=$(echo -n "$DATA" | openssl dgst -sha512 -sign "$PRIVATE_KEY_FILE" | b64enc)JWT="${DATA}.${SIGNATURE}"
echo "$JWT"
# --- Request access token ---echo "🔐 Request to $TOKEN_URL ..."RESPONSE=$(curl --fail -sS -X POST "$TOKEN_URL" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \ -d "assertion=$JWT") || { echo "❌ Error acquiring token" exit 1}
# --- Extract access token ---ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.access_token')
if [[ "$ACCESS_TOKEN" == "null" || -z "$ACCESS_TOKEN" ]]; then echo "❌ Did not receive access token!" echo "$RESPONSE" exit 1fi
# --- Output ---echo "✅ Received access token:"echo "$ACCESS_TOKEN"
# --- Cleanup ---rm -f "$PRIVATE_KEY_FILE"Manual implementation
Section titled “Manual implementation”To manually acquire a short-lived access token, you need to create and sign a JWT first. Thesefields are needed:
Header:
Section titled “Header:”kid: Populate this field by extracting the corresponding key from service-account.jsonalg: Your signature algorithm. We recommend “RS512”typ: “JWT”
Payload:
Section titled “Payload:”iss: Populate this field by extracting the corresponding key from service-account.jsonsub: Populate this field by extracting the corresponding key from service-account.jsonaud: Populate this field by extracting the corresponding key from service-account.jsonjti: Populate this field by generating a uuidv4-stringiat: Populate this field with the present time in epoch time format in your local timeexp: Populate this field with the present time (local time) + 600 seconds in epoch time format
The following PowerShell script implements all those tasks. Please use it as a reference for your manual implementations:
Refer to the Request short lived API token documentation in the API Explorer.
Use the following PowerShell script to retrieve an access token on Windows.
Prerequisites
- PowerShell 5.1 or later (included in Windows 10/11) or PowerShell Core
- A STACKIT service account with a valid JSON configuration file
Steps to acquire an access token using the PowerShell script:
-
Download your service account configuration from the STACKIT Portal and save it as
service-account.json. -
Copy the script
Get-StackitAccessToken.ps1from here. -
Open PowerShell and navigate to the directory containing the script.
-
Run the script:
Terminal window .\Get-StackitAccessToken.ps1Alternatively, specify a custom path to the configuration file:
Terminal window .\Get-StackitAccessToken.ps1 -ConfigPath "C:\path\to\service-account.json" -
The script outputs the access token. To use it for API requests:
Terminal window $AccessToken = .\Get-StackitAccessToken.ps1 | Select-Object -Last 1$Headers = @{ "Authorization" = "Bearer $AccessToken" }Invoke-RestMethod -Uri "https://api.stackit.cloud/v1/..." -Headers $Headers
PowerShell Script
Section titled “PowerShell Script”<#.SYNOPSIS Retrieves a STACKIT access token using a service account.
.DESCRIPTION This script authenticates with the STACKIT Identity Provider using a service account JSON configuration file and returns an access token. It creates a signed JWT (RS512) and exchanges it for an access token.
.PARAMETER ConfigPath Path to the service account JSON configuration file. Default: service-account.json
.EXAMPLE .\Get-StackitAccessToken.ps1
.EXAMPLE .\Get-StackitAccessToken.ps1 -ConfigPath "C:\path\to\service-account.json"
.NOTES Cross-platform compatible script.
Windows (PowerShell 5.1+): - Uses CNG (Cryptography Next Generation) RSA signing - Requires .NET Framework 4.6+
Linux/macOS (PowerShell Core/7+): - Uses ImportPkcs8PrivateKey or ImportFromPem (.NET 5+)
Tested on: - Windows PowerShell 5.1 - PowerShell Core 7.x on Windows/Linux/macOS#>
[CmdletBinding()]param( [Parameter(Mandatory = $false)] [string]$ConfigPath = "service-account.json")
Set-StrictMode -Version Latest$ErrorActionPreference = "Stop"
# Display version information for debugging$PSVersion = $PSVersionTable.PSVersion$IsPwshCore = $PSVersionTable.PSVersion.Major -ge 6 -or $PSVersionTable.PSEdition -eq "Core"Write-Host "PowerShell: v$PSVersion $(if ($IsPwshCore) { '(Core)' } else { '(Windows)' })" -ForegroundColor Gray
$TokenUrl = "https://service-account.api.stackit.cloud/token"
function ConvertTo-Base64Url { param([byte[]]$Bytes) return [Convert]::ToBase64String($Bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_')}
function ConvertTo-Base64UrlFromString { param([string]$Text) return ConvertTo-Base64Url -Bytes ([System.Text.Encoding]::UTF8.GetBytes($Text))}
function Invoke-RsaSigning { param( [string]$PrivateKeyPem, [byte[]]$DataToSign )
# Extract Base64 content from PEM $KeyContent = $PrivateKeyPem -replace "-----BEGIN PRIVATE KEY-----", "" ` -replace "-----END PRIVATE KEY-----", "" ` -replace "-----BEGIN RSA PRIVATE KEY-----", "" ` -replace "-----END RSA PRIVATE KEY-----", "" ` -replace "\s", ""
$KeyBytes = [Convert]::FromBase64String($KeyContent)
# Method 1: Try CNG approach (Windows PowerShell 5.1+) if ([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform([System.Runtime.InteropServices.OSPlatform]::Windows)) { try { Write-Host "Attempting CNG RSA import..." -ForegroundColor Gray $CertFactory = [System.Security.Cryptography.CngKey]::Import($KeyBytes, [System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob) $RsaCng = New-Object System.Security.Cryptography.RSACng($CertFactory)
$SignatureBytes = $RsaCng.SignData($DataToSign, [System.Security.Cryptography.HashAlgorithmName]::SHA512, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) Write-Host "JWT signed successfully (CNG method)" -ForegroundColor Green return $SignatureBytes } catch { Write-Host "CNG method failed: $($_.Exception.Message)" -ForegroundColor Yellow } }
# Method 2: Try ImportPkcs8PrivateKey (cross-platform, available in .NET 5+) try { Write-Host "Attempting ImportPkcs8PrivateKey method..." -ForegroundColor Gray $Rsa = [System.Security.Cryptography.RSA]::Create() $Rsa.ImportPkcs8PrivateKey($KeyBytes, [ref]$null)
$SignatureBytes = $Rsa.SignData($DataToSign, [System.Security.Cryptography.HashAlgorithmName]::SHA512, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) Write-Host "JWT signed successfully (ImportPkcs8PrivateKey method)" -ForegroundColor Green return $SignatureBytes } catch { Write-Host "ImportPkcs8PrivateKey method not available: $($_.Exception.Message)" -ForegroundColor Yellow }
# Method 3: Try ImportFromPem (PowerShell 7.2+, .NET 6+) try { Write-Host "Attempting ImportFromPem method..." -ForegroundColor Gray $Rsa = [System.Security.Cryptography.RSA]::Create() $Rsa = [System.Security.Cryptography.RSA]::ImportFromPem($PrivateKeyPem)
$SignatureBytes = $Rsa.SignData($DataToSign, [System.Security.Cryptography.HashAlgorithmName]::SHA512, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) Write-Host "JWT signed successfully (ImportFromPem method)" -ForegroundColor Green return $SignatureBytes } catch { Write-Host "ImportFromPem method not available: $($_.Exception.Message)" -ForegroundColor Yellow }
Write-Error @"Unable to import RSA private key. This script requires:PowerShell 5.1+ on Windows (CNG support), ORPowerShell Core/7+ (.NET 5+) with ImportPkcs8PrivateKey or ImportFromPem
Current: PowerShell v$($PSVersionTable.PSVersion) on $([System.Runtime.InteropServices.RuntimeInformation]::OSDescription)"@ exit 1}
if (-not (Test-Path -Path $ConfigPath)) { Write-Error "Configuration file not found: $ConfigPath" exit 1}
# Resolve to absolute path for cross-platform compatibility$ConfigPath = (Resolve-Path -Path $ConfigPath).ProviderPath
Write-Host "Reading configuration..." -ForegroundColor Cyan$Config = Get-Content -Path $ConfigPath -Raw | ConvertFrom-Json$Credentials = $Config.credentials
$Iss = $Credentials.iss$Sub = $Credentials.sub$Aud = $Credentials.aud$Kid = $Credentials.kid$PrivateKeyPem = $Credentials.privateKey -replace '\\n', "`n"
$Now = [DateTimeOffset]::UtcNow.ToUnixTimeSeconds()$Exp = $Now + 600$Jti = [Guid]::NewGuid().ToString()
$Header = @{ alg = "RS512"; typ = "JWT"; kid = $Kid } | ConvertTo-Json -Compress$Payload = @{ iss = $Iss; sub = $Sub; aud = $Aud; iat = $Now; exp = $Exp; jti = $Jti } | ConvertTo-Json -Compress
$HeaderB64 = ConvertTo-Base64UrlFromString -Text $Header$PayloadB64 = ConvertTo-Base64UrlFromString -Text $Payload$DataToSign = "$HeaderB64.$PayloadB64"
Write-Host "Signing JWT..." -ForegroundColor Cyan
try { $DataBytes = [System.Text.Encoding]::UTF8.GetBytes($DataToSign) $SignatureBytes = Invoke-RsaSigning -PrivateKeyPem $PrivateKeyPem -DataToSign $DataBytes $SignatureB64 = ConvertTo-Base64Url -Bytes $SignatureBytes}catch { Write-Error "JWT signing failed: $($_.Exception.Message)" exit 1}
$Jwt = "$DataToSign.$SignatureB64"Write-Host "Requesting token..." -ForegroundColor Cyan
$Body = @{ grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer" assertion = $Jwt}
try { $Response = Invoke-RestMethod -Uri $TokenUrl -Method Post -ContentType "application/x-www-form-urlencoded" -Body $Body Write-Host "Success!" -ForegroundColor Green $Response.access_token}catch { Write-Error "Error in the request: $($_.Exception.Message)"}