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! 🎯

Image description
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! 🚀