Skip to content

Instantly share code, notes, and snippets.

@rleap-m
Created November 13, 2025 18:41
Show Gist options
  • Select an option

  • Save rleap-m/3f1f66924a7263f93e46c6147fac1654 to your computer and use it in GitHub Desktop.

Select an option

Save rleap-m/3f1f66924a7263f93e46c6147fac1654 to your computer and use it in GitHub Desktop.
Script which will obtain access and refresh tokens to interact with MKE4 /api/auth/v1/accounts endpoints
#!/usr/bin/env bash
set -euo pipefail
# ============================================
# MKE / Dex OAuth2 PKCE token fetcher (bash-only)
# - Auth Code + PKCE: interactive (copy/paste code)
# - Refresh grant: non-interactive
#
# deps: bash, curl, openssl, base64, tr, sed
# (jq optional; script falls back to sed)
# ============================================
# Defaults
ADDRESS="" # mkectl-style flag name
CLIENT_ID="mke-dashboard" # Only audience registered in Dex (at the time of the script writing)
SCOPES="openid profile email groups offline_access"
REDIRECT_URI="https://127.0.0.1:3000" # To see the accepted redirects for mke-dashboard run:
# kubectl get clusterdeployments.k0rdent.mirantis.com/self-adopted-cluster-mke -n k0rdent -o yaml | grep staticClients -A25
AUTH_PATH="/dex/auth"
TOKEN_PATH="/dex/token"
OUT_FILE="token.json"
CODE=""
REFRESH_TOKEN=""
QUIET=0
CURL_OPTS=() # holds curl flags (e.g., -k for insecure)
usage() {
cat <<EOF
Usage:
$0 --address <mke-address> [options]
Flags:
-a, --address string Address of the MKE 4k cluster, e.g. my-mke-cluster.example.com [REQUIRED]
(If no scheme is provided, https:// will be prefixed automatically.)
Options:
--client-id ID Dex client_id (default: ${CLIENT_ID})
--scopes "..." OAuth scopes (default: ${SCOPES})
--redirect-uri URL Redirect URI registered in Dex (default: ${REDIRECT_URI})
--auth-path PATH Auth endpoint path (default: ${AUTH_PATH})
--token-path PATH Token endpoint path (default: ${TOKEN_PATH})
--out FILE Where to write token JSON (default: ${OUT_FILE})
--code CODE Provide the authorization code directly (skip browser step)
--refresh TOKEN Use refresh_token grant to rotate tokens
-k, --insecure Skip TLS verification for curl (testing only)
-q, --quiet Suppress extra output; only write ${OUT_FILE}
-h, --help Show this help
Examples:
# Interactive PKCE (copy/paste code; OOB redirect)
$0 --address 3d1wgb-mke4-lb-9fc5efb34d95595b.elb.us-east-2.amazonaws.com
# Refresh later without browser:
$0 -a 3d1wgb-mke4-lb-9fc5efb34d95595b.elb.us-east-2.amazonaws.com --refresh \$(jq -r .refresh_token token.json)
# Ignore TLS errors (testing only):
$0 -a 3d1wgb-mke4-lb-9fc5efb34d95595b.elb.us-east-2.amazonaws.com --insecure
EOF
}
# tiny URL encoder (no python/jq)
urlencode() {
local s="$1" i c o=""
for (( i=0; i<${#s}; i++ )); do
c="${s:$i:1}"
case "$c" in
[a-zA-Z0-9.~_-]) o+="$c" ;;
*) printf -v o '%s%%%02X' "$o" "'$c" ;;
esac
done
printf '%s' "$o"
}
have_jq() { command -v jq >/dev/null 2>&1; }
# parse args
while [[ $# -gt 0 ]]; do
case "$1" in
-a|--address) ADDRESS="$2"; shift 2;;
--client-id) CLIENT_ID="$2"; shift 2;;
--scopes) SCOPES="$2"; shift 2;;
--redirect-uri) REDIRECT_URI="$2"; shift 2;;
--auth-path) AUTH_PATH="$2"; shift 2;;
--token-path) TOKEN_PATH="$2"; shift 2;;
--out) OUT_FILE="$2"; shift 2;;
--code) CODE="$2"; shift 2;;
--refresh) REFRESH_TOKEN="$2"; shift 2;;
-k|--insecure) CURL_OPTS+=(-k); shift;;
-q|--quiet) QUIET=1; shift;;
-h|--help) usage; exit 0;;
*) echo "Unknown arg: $1" >&2; usage; exit 1;;
esac
done
if [[ -z "$ADDRESS" ]]; then
echo "Error: --address is required" >&2
usage; exit 1
fi
# Normalize ADDRESS → HOST with scheme, then trim trailing slash
if [[ "$ADDRESS" =~ ^https?:// ]]; then
HOST="$ADDRESS"
else
HOST="https://$ADDRESS"
fi
HOST="${HOST%/}"
AUTH_URL_BASE="${HOST}${AUTH_PATH}"
TOKEN_URL="${HOST}${TOKEN_PATH}"
# =========================
# Refresh token flow (if requested)
# =========================
if [[ -n "$REFRESH_TOKEN" ]]; then
[[ $QUIET -eq 0 ]] && echo "Refreshing access token via ${TOKEN_URL} ..."
RESP="$(curl "${CURL_OPTS[@]}" -sS -X POST "${TOKEN_URL}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=${REFRESH_TOKEN}" \
-d "client_id=${CLIENT_ID}")"
echo "$RESP" > "$OUT_FILE"
if have_jq; then
ACCESS=$(jq -r '.access_token // empty' "$OUT_FILE")
REFRESH=$(jq -r '.refresh_token // empty' "$OUT_FILE")
else
ACCESS=$(sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p' "$OUT_FILE")
REFRESH=$(sed -n 's/.*"refresh_token":"\([^"]*\)".*/\1/p' "$OUT_FILE")
fi
[[ $QUIET -eq 0 ]] && {
echo "Wrote tokens to ${OUT_FILE}"
[[ -n "$ACCESS" ]] && echo "Access token length: ${#ACCESS}"
[[ -n "$REFRESH" ]] && echo "Refresh token length: ${#REFRESH}"
echo
echo "Try the Accounts API:"
echo " curl -H \"Authorization: Bearer ${ACCESS}\" \"${HOST}/api/auth/v1/orgs\""
echo
echo "Export helpers:"
echo " export MKE_ACCESS_TOKEN='${ACCESS}'"
[[ -n "$REFRESH" ]] && echo " export MKE_REFRESH_TOKEN='${REFRESH}'"
}
exit 0
fi
# =========================
# PKCE Auth Code flow
# =========================
# Generate PKCE verifier/challenge (URL-safe base64 without '=')
VERIFIER="$(head -c 32 /dev/urandom | base64 | tr '+/' '-_' | tr -d '=')"
CHALLENGE="$(printf %s "$VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')"
SCOPES_ENC="$(printf %s "$SCOPES" | sed 's/ /%20/g')"
REDIRECT_URI_ENC="$(urlencode "$REDIRECT_URI")"
if [[ -z "$CODE" ]]; then
AUTH_URL="${AUTH_URL_BASE}?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI_ENC}&response_type=code&scope=${SCOPES_ENC}&code_challenge=${CHALLENGE}&code_challenge_method=S256"
[[ $QUIET -eq 0 ]] && {
echo "Open this URL, log in, then copy the authorization code shown by Dex (OOB redirect):"
echo
echo " ${AUTH_URL}"
echo
}
read -r -p "Paste authorization code here: " CODE
fi
[[ -z "$CODE" ]] && { echo "No code provided. Aborting." >&2; exit 1; }
# Exchange code for tokens
[[ $QUIET -eq 0 ]] && echo "Exchanging code for tokens at ${TOKEN_URL} ..."
RESP="$(curl "${CURL_OPTS[@]}" -sS -X POST "${TOKEN_URL}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=${CODE}" \
-d "client_id=${CLIENT_ID}" \
-d "redirect_uri=${REDIRECT_URI}" \
-d "code_verifier=${VERIFIER}")"
echo "$RESP" > "$OUT_FILE"
# Extract tokens (jq preferred; sed fallback)
if have_jq; then
ACCESS=$(jq -r '.access_token // empty' "$OUT_FILE")
REFRESH=$(jq -r '.refresh_token // empty' "$OUT_FILE")
IDTOK=$(jq -r '.id_token // empty' "$OUT_FILE")
else
ACCESS=$(echo "$RESP" | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p')
REFRESH=$(echo "$RESP" | sed -n 's/.*"refresh_token":"\([^"]*\)".*/\1/p')
IDTOK=$(echo "$RESP" | sed -n 's/.*"id_token":"\([^"]*\)".*/\1/p')
fi
[[ $QUIET -eq 0 ]] && {
echo "Wrote tokens to ${OUT_FILE}"
[[ -n "$ACCESS" ]] && echo "Access token length: ${#ACCESS}"
[[ -n "$REFRESH" ]] && echo "Refresh token length: ${#REFRESH}"
echo
echo "Use with Accounts API (example):"
echo " curl -H \"Authorization: Bearer ${ACCESS}\" \"${HOST}/api/auth/v1/orgs\""
echo
echo "Export helpers:"
echo " export MKE_ACCESS_TOKEN='${ACCESS}'"
[[ -n "$REFRESH" ]] && echo " export MKE_REFRESH_TOKEN='${REFRESH}'"
[[ -n "$IDTOK" ]] && echo " export MKE_ID_TOKEN='${IDTOK}'"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment