If you're launching your SaaS on AppSumo, integrating with their API is crucial for a smooth user experience. This guide walks you through the AppSumo authentication and license verification process, using a fully working Ruby on Rails example.
This article was inspired by RobinReach’s AppSumo integration.
Check out RobinReach for automated social media management! 🎯
Whether you're a founder or developer, this guide will help you integrate AppSumo seamlessly.
Why Integrate with AppSumo?
AppSumo offers lifetime deals (LTDs) to a large number of users.
To streamline onboarding and license verification, they provide an OpenID-based authentication system. By integrating with AppSumo's API, you can:
- Verify purchases and activate licenses automatically
- Handle license upgrades/downgrades
- Respond to AppSumo webhook events
- Improve user onboarding
Step 1: Setting Up the Authentication Flow
The first step in the integration is to set up an authentication flow that allows users to sign in via AppSumo.
1.1 Create an OAuth Redirect to AppSumo
In AppsumoAuthController
, we define a method to generate the OAuth authorization URL and redirect users:
class AppsumoAuthController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
CLIENT_ID = Rails.application.credentials.appsumo.client_id
REDIRECT_URI = 'https://robinreach.com/appsumo/callback'
def redirect
auth_url = "https://appsumo.com/openid/authorize?client_id=#{CLIENT_ID}&response_type=code&redirect_uri=#{REDIRECT_URI}"
redirect_to auth_url, allow_other_host: true
end
end
This method constructs the OAuth authorization URL, allowing users to authenticate via AppSumo. Upon successful authentication, users are redirected to the specified callback URL.
1.2 Handle the Callback and Exchange Code for an Access Token
When users approve the authentication, AppSumo redirects them back with an authorization code. We exchange this code for an access token:
def callback
code = params[:code]
return redirect_to auth_url if code.blank?
response = fetch_access_token(code)
if response['access_token']
session[:appsumo_access_token] = response['access_token']
session[:appsumo_refresh_token] = response['refresh_token']
redirect_to appsumo_license_path
else
render json: { error: response['error'] || 'Failed to authenticate' }, status: :unauthorized
end
end
The fetch_access_token
method sends a request to AppSumo to retrieve the access token:
def fetch_access_token(code)
response = self.class.post('/token/', headers: { 'Content-Type' => 'application/json' }, body: {
client_id: CLIENT_ID,
client_secret: Rails.application.credentials.appsumo.client_secret,
code: code,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code'
}.to_json)
response.parsed_response
end
This step is essential for securely retrieving an access token, which will be used for further API requests.
Step 2: Fetch and Validate the License Key
Once authenticated, we need to fetch the license key to check if the user has a valid AppSumo purchase
def fetch_license
access_token = session[:appsumo_access_token]
if access_token
response = self.class.get("/license_key/", query: { access_token: access_token })
if response.success?
license_key = response.parsed_response["license_key"]
handle_license_verification(license_key)
else
refresh_access_token
end
else
redirect_to new_user_session_path
end
end
This method retrieves the license key and checks if it belongs to an existing Company. If not, the user is directed to sign up.
Step 3: Handling Webhook Events
AppSumo sends webhooks for key events like purchases, upgrades, and deactivations. We need to process them accordingly.
def webhook
payload = JSON.parse(request.body.read)
license_key = payload['license_key']
event = payload['event']
tier = payload['tier'].to_i
case event
when 'activate', 'purchase'
REDIS.set(license_key, { license_key: license_key, tier: tier }.to_json, ex: 60 * 60 * 24 * 60)
render json: { success: true, event: event }, status: :ok
when 'upgrade', 'downgrade'
update_license(license_key, payload['prev_license_key'], tier)
when 'deactivate'
deactivate_license(license_key)
else
render json: { success: false, error: 'Unknown event' }, status: :bad_request
end
end
Why Store in Redis?
We use Redis to temporarily store the license data for quick access. This reduces the number of database queries and speeds up license verification. The data is set to expire after 60 days, ensuring that stale licenses are not kept indefinitely.
Updating the Company Based on the Event
For events like purchases or upgrades, we update the Company record to reflect the new subscription tier:
def update_company_license(license_key, tier)
company = Company.find_by(license_key: license_key)
if company
company.update(plan_tier: tier)
else
Company.create(license_key: license_key, plan_tier: tier)
end
end
This ensures that companies have the correct access level based on their AppSumo purchase.
Step 4: Securing Webhooks with Signature Verification
Since webhooks can be exploited, we verify requests using HMAC-SHA256 signatures:
def verify_signature
timestamp = request.headers['X-Appsumo-Timestamp']
signature = request.headers['X-Appsumo-Signature']
body = request.raw_post
return render json: { success: false, error: 'Missing headers' }, status: :unauthorized unless timestamp && signature && body
message = "#{timestamp}#{body}"
calculated_signature = OpenSSL::HMAC.hexdigest('SHA256', API_KEY, message)
unless ActiveSupport::SecurityUtils.secure_compare(signature, calculated_signature)
render json: { success: false, error: 'Invalid signature' }, status: :unauthorized
end
end
This prevents unauthorized requests and protects your system from fraudulent webhooks.
Final Thoughts
Integrating AppSumo’s API into your SaaS can automate user onboarding, license management etc.
Key Takeaways:
✅ Implement OAuth authentication for AppSumo users
✅ Retrieve and validate AppSumo license keys
✅ Handle webhook events for upgrades, downgrades, and deactivations
✅ Secure webhooks using signature verification
This integration ensures that your SaaS can handle AppSumo deals efficiently while providing a seamless experience to users.
🔗 Next Steps:
- Test OAuth flow and webhook processing.
- Monitor webhook logs for debugging.
For more details, refer to the AppSumo Licensing Guide.
This guide is inspired by RobinReach’s integration with AppSumo. Discover how RobinReach simplifies social media management with automation and smart scheduling! 🚀