#!/usr/bin/env bash # gstack-auth-refresh — silently refresh auth token if expired # # Usage: # gstack-auth-refresh — refresh and print access token # gstack-auth-refresh --check — exit 0 if authenticated, 1 if not # # Called by gstack-community-backup and other authenticated scripts. # If the refresh token is also expired, prints an error and exits 1. # # Env overrides (for testing): # GSTACK_STATE_DIR — override ~/.gstack state directory # GSTACK_DIR — override auto-detected gstack root set -euo pipefail GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}" STATE_DIR="${GSTACK_STATE_DIR:-$HOME/.gstack}" AUTH_FILE="$STATE_DIR/auth-token.json" # Source Supabase config if [ -f "$GSTACK_DIR/supabase/config.sh" ]; then . "$GSTACK_DIR/supabase/config.sh" fi SUPABASE_URL="${GSTACK_SUPABASE_URL:-}" ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}" AUTH_URL="${SUPABASE_URL}/auth/v1" # ─── Helper: extract JSON field ────────────────────────────── json_field() { local json="$1" local field="$2" echo "$json" | jq -r ".${field}" 2>/dev/null | sed 's/null//' } # ─── Check auth file exists ───────────────────────────────── if [ ! -f "$AUTH_FILE" ]; then if [ "${1:-}" = "--check" ]; then exit 1 fi echo "Not authenticated. Run: gstack auth " >&2 exit 1 fi AUTH_JSON="$(cat "$AUTH_FILE")" ACCESS_TOKEN="$(json_field "$AUTH_JSON" "access_token")" REFRESH_TOKEN="$(json_field "$AUTH_JSON" "refresh_token")" EXPIRES_AT="$(json_field "$AUTH_JSON" "expires_at")" EMAIL="$(json_field "$AUTH_JSON" "email")" USER_ID="$(json_field "$AUTH_JSON" "user_id")" NOW="$(date +%s)" # ─── Check-only mode ──────────────────────────────────────── if [ "${1:-}" = "--check" ]; then [ -n "$ACCESS_TOKEN" ] && exit 0 || exit 1 fi # ─── Token still valid? Return it. ─────────────────────────── # Add 60s buffer to avoid using a token that's about to expire BUFFER=60 if [ -n "$EXPIRES_AT" ] && [ "$NOW" -lt "$(( EXPIRES_AT - BUFFER ))" ] 2>/dev/null; then echo "$ACCESS_TOKEN" exit 0 fi # ─── Token expired — refresh it ───────────────────────────── if [ -z "$REFRESH_TOKEN" ] || [ "$REFRESH_TOKEN" = "null" ]; then echo "Session expired and no refresh token. Run: gstack auth " >&2 exit 1 fi if [ -z "$SUPABASE_URL" ] || [ -z "$ANON_KEY" ]; then echo "Error: Supabase not configured" >&2 exit 1 fi REFRESH_RESPONSE="$(curl -s --max-time 10 \ -X POST "${AUTH_URL}/token?grant_type=refresh_token" \ -H "Content-Type: application/json" \ -H "apikey: ${ANON_KEY}" \ -d "{\"refresh_token\":\"${REFRESH_TOKEN}\"}" \ 2>/dev/null || echo "{}")" NEW_ACCESS="$(json_field "$REFRESH_RESPONSE" "access_token")" NEW_REFRESH="$(json_field "$REFRESH_RESPONSE" "refresh_token")" NEW_EXPIRES_IN="$(json_field "$REFRESH_RESPONSE" "expires_in")" if [ -z "$NEW_ACCESS" ] || [ "$NEW_ACCESS" = "null" ]; then echo "Session expired. Run: gstack auth " >&2 rm -f "$AUTH_FILE" exit 1 fi # Update token file NEW_EXPIRES_AT=$(( NOW + ${NEW_EXPIRES_IN:-3600} )) cat > "$AUTH_FILE" <