#!/usr/bin/env bash set -euo pipefail TAPAUTH_BASE="${TAPAUTH_BASE_URL:-https://tapauth.ai}" TAPAUTH_AGENT="${TAPAUTH_AGENT_NAME:-tapauth-skill}" if [ -n "${TAPAUTH_HOME:-}" ]; then TAPAUTH_DIR="$TAPAUTH_HOME" elif [ -n "${CLAUDE_PLUGIN_DATA:-}" ]; then TAPAUTH_DIR="$CLAUDE_PLUGIN_DATA" else TAPAUTH_DIR="./.tapauth" fi mkdir -p "$TAPAUTH_DIR" && chmod 700 "$TAPAUTH_DIR" provider="${1:-}" raw_scopes="${2:-}" if [ -z "${provider:-}" ]; then echo "usage: tapauth " >&2 echo " providers: google, github, linear, vercel, slack, notion, asana, sentry, discord" >&2 exit 1 fi if [ -z "${raw_scopes:-}" ]; then echo "tapauth: scopes are required for provider '$provider'" >&2 echo "usage: tapauth " >&2 exit 1 fi scopes="$raw_scopes" sorted_scopes=$(echo "$scopes" | tr "," "\n" | sort | tr "\n" "," | sed "s/,$//") safe_scopes=$(echo "$sorted_scopes" | tr '/:' '__') env_file="${TAPAUTH_DIR}/${provider}-${safe_scopes}.env" # --- Cached flow --- if [ -f "$env_file" ]; then source "$env_file" if [ -n "${TAPAUTH_EXPIRES:-}" ] && [ "$(date +%s)" -lt "${TAPAUTH_EXPIRES:-0}" ]; then echo "${TAPAUTH_TOKEN:-}" exit 0 fi # Refresh TAPAUTH_TOKEN="" TAPAUTH_EXPIRES="" eval "$(curl -sf -H "Authorization: Bearer ${TAPAUTH_GRANT_SECRET}" \ -H 'Accept: text/plain' "${TAPAUTH_BASE}/api/v1/grants/${TAPAUTH_GRANT_ID}" | grep '^TAPAUTH_[A-Z_]*=')" 2>/dev/null || true if [ -n "${TAPAUTH_TOKEN:-}" ]; then install -m 600 /dev/null "$env_file" cat > "$env_file" <&2 exit 1 fi # --- First-run flow --- echo "Creating grant for ${provider} (${sorted_scopes})..." >&2 TAPAUTH_GRANT_ID="" TAPAUTH_GRANT_SECRET="" TAPAUTH_APPROVE_URL="" eval "$(curl -sf -X POST -H 'Accept: text/plain' \ --data-urlencode "provider=${provider}" \ --data-urlencode "scopes=${sorted_scopes}" \ --data-urlencode "agent_name=${TAPAUTH_AGENT}" \ "${TAPAUTH_BASE}/api/v1/grants" | grep '^TAPAUTH_[A-Z_]*=')" || true if [ -z "${TAPAUTH_GRANT_ID:-}" ] || [ -z "${TAPAUTH_GRANT_SECRET:-}" ]; then echo "tapauth: failed to create grant" >&2 exit 1 fi echo "Approve access: ${TAPAUTH_APPROVE_URL:-}" >&2 # Poll — same endpoint poll_start=$SECONDS while true; do sleep 2 elapsed=$((SECONDS - poll_start)) [ "$elapsed" -ge 600 ] && { echo "tapauth: timed out" >&2; exit 1; } echo "Waiting for approval... (${elapsed}s)" >&2 TAPAUTH_TOKEN="" eval "$(curl -sf -H "Authorization: Bearer ${TAPAUTH_GRANT_SECRET}" \ -H 'Accept: text/plain' "${TAPAUTH_BASE}/api/v1/grants/${TAPAUTH_GRANT_ID}" | grep '^TAPAUTH_[A-Z_]*=')" 2>/dev/null || true [ -n "${TAPAUTH_TOKEN:-}" ] && break # Check for terminal error case "${TAPAUTH_STATUS:-}" in expired|revoked|denied|link_expired) echo "tapauth: grant ${TAPAUTH_STATUS}" >&2; exit 1 ;; esac done # Cache install -m 600 /dev/null "$env_file" cat > "$env_file" <