Skip to content

Instantly share code, notes, and snippets.

@ivorpad
Created July 25, 2024 16:48
Show Gist options
  • Save ivorpad/d0e427438a6d94dd9593dc24d1053f5f to your computer and use it in GitHub Desktop.
Save ivorpad/d0e427438a6d94dd9593dc24d1053f5f to your computer and use it in GitHub Desktop.
This script is a Bash utility for managing OAuth 2.0 authentication with the Xero API.
#!/bin/bash
source ./send_email.sh
# OAuth 2.0 configuration
CLIENT_ID=""
CLIENT_SECRET=""
REDIRECT_URI="http://localhost:3000/api/xoauth/callback"
AUTH_URL="https://login.xero.com/identity/connect/authorize"
TOKEN_URL="https://identity.xero.com/connect/token"
SCOPES="openid profile email accounting.attachments.read accounting.budgets.read accounting.contacts.read accounting.journals.read accounting.reports.read accounting.reports.tenninetynine.read accounting.settings.read accounting.transactions.read assets.read offline_access"
REDIS_URL=""
save_tokens_to_redis() {
local tokens="$1"
/usr/local/bin/redis-cli -u "$REDIS_URL" SET xero_tokens "$tokens"
}
save_state_to_redis() {
local state="$1"
/usr/local/bin/redis-cli -u "$REDIS_URL" SET xero_state:$state "$state"
}
get_tokens_from_redis() {
/usr/local/bin/redis-cli -u "$REDIS_URL" GET xero_tokens
}
get_state_from_redis() {
local state="$1"
/usr/local/bin/redis-cli -u "$REDIS_URL" GET xero_state:$state
}
generate_auth_url() {
STATE=$(openssl rand -hex 16)
AUTH_REQUEST_URL="${AUTH_URL}?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPES}&state=${STATE}"
save_state_to_redis "$STATE"
echo "$AUTH_REQUEST_URL"
}
refresh_token() {
local refresh_token="$1"
TOKEN_RESPONSE=$(curl -s -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}" \
-d "client_secret=${CLIENT_SECRET}")
if echo "$TOKEN_RESPONSE" | jq -e '.access_token' > /dev/null; then
echo "Token refreshed successfully."
save_tokens_to_redis "$TOKEN_RESPONSE"
echo "New tokens saved to Redis."
else
echo "Error refreshing token. Response:"
echo "$TOKEN_RESPONSE"
AUTH_URL=$(generate_auth_url)
AUTH_URL=$(echo "$AUTH_URL" | sed 's/^OK[[:space:]]*//' | tr -d '\n')
TEXT_MESSAGE="Token refresh failed. Please re-authorize: $AUTH_URL"
HTML_MESSAGE="Token refresh failed. Please <a href=\"$AUTH_URL\">re-authorize</a>"
send_email "$TEXT_MESSAGE" "$HTML_MESSAGE"
exit 1
fi
}
exchange_code_for_tokens() {
local auth_code="$1"
TOKEN_RESPONSE=$(curl -s -X POST ${TOKEN_URL} \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=${auth_code}" \
-d "redirect_uri=${REDIRECT_URI}" \
-d "client_id=${CLIENT_ID}" \
-d "client_secret=${CLIENT_SECRET}")
if echo "$TOKEN_RESPONSE" | jq -e '.access_token' > /dev/null; then
echo "Authorization code exchanged successfully."
save_tokens_to_redis "$TOKEN_RESPONSE"
echo "Tokens saved to Redis."
else
echo "Error exchanging authorization code. Response:"
echo "$TOKEN_RESPONSE"
exit 1
fi
}
case "$1" in
--refresh)
echo "Refreshing token..."
STORED_TOKENS=$(get_tokens_from_redis)
REFRESH_TOKEN=$(echo $STORED_TOKENS | jq -r '.refresh_token')
if [ -z "$REFRESH_TOKEN" ]; then
echo "Error: Refresh token not found in Redis"
AUTH_URL=$(generate_auth_url)
AUTH_URL=$(echo "$AUTH_URL" | sed 's/^OK[[:space:]]*//' | tr -d '\n')
TEXT_MESSAGE="Refresh token not found in Redis: $REDIS_URL. Please re-authorize: $AUTH_URL"
HTML_MESSAGE="Refresh token not found in Redis: $REDIS_URL. Please <a href=\"$AUTH_URL\">re-authorize</a>"
send_email "$TEXT_MESSAGE" "$HTML_MESSAGE"
exit 1
fi
refresh_token "$REFRESH_TOKEN"
;;
--code)
if [ -z "$2" ]; then
echo "Error: Authorization code not provided"
exit 1
fi
echo "Exchanging authorization code for tokens..."
exchange_code_for_tokens "$2"
;;
"")
# Generate a random state value
STATE=$(openssl rand -hex 16)
# Construct the authorization URL
AUTH_REQUEST_URL=$(generate_auth_url)
echo "Please visit this URL in a browser on your local machine to authorize the application:"
echo $AUTH_REQUEST_URL
echo
echo "After authorization, you will be redirected to a URL starting with $REDIRECT_URI"
echo "Look for the 'code' parameter in this URL."
echo
# Wait for the authorization code
read -p "Enter the authorization code from the redirect URL: " AUTH_CODE
exchange_code_for_tokens "$AUTH_CODE"
;;
*)
echo "Usage: $0 [--refresh | --code <authorization_code>]"
exit 1
;;
esac
# Use the new access token to update configuration
STORED_TOKENS=$(get_tokens_from_redis)
NEW_ACCESS_TOKEN=$(echo $STORED_TOKENS | jq -r '.access_token')
CURL_RESPONSE=$(curl --request PATCH \
--url 'http://localhost:8000/api/public/v1/sources/<source_id>' \
--header 'accept: application/json' \
--header 'authorization: Basic base64(username:password)' \
--header 'Content-Type: application/json' \
--data "{
\"configuration\": {
\"credentials\": {
\"access_token\": \"$NEW_ACCESS_TOKEN\"
}
}
}")
echo "CURL Response:"
echo "$CURL_RESPONSE"
if echo "$CURL_RESPONSE" | jq -e '.sourceId' > /dev/null; then
echo "Configuration updated successfully."
echo "Updated source details:"
echo "$CURL_RESPONSE" | jq '.'
else
echo "Error updating configuration. Response:"
echo "$CURL_RESPONSE"
send_email "Error updating configuration: $CURL_RESPONSE" "Error updating configuration: $CURL_RESPONSE"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment