arsduo/koala · error · Koala::Facebook::OAuthSignatureError

Invalid (incomplete) signature data

Error message

Invalid (incomplete) signature data

What it means

Koala::Facebook::OAuthSignatureError is raised by OAuth#parse_signed_request when the input lacks the two-part signature.payload shape: input.split(".", 2) must yield both an encoded signature and an encoded envelope. If the string contains no dot, encoded_envelope is nil and the method raises Invalid (incomplete) signature data rather than guessing. This is the entry guard for every Facebook signed_request value, including the fbsr_<app_id> cookie parsed by parse_signed_cookie and get_user_info_from_cookies.

Source

Thrown at lib/koala/oauth.rb:240

      # @param (see #exchange_access_token_info)
      #
      # @return A new access token or the existing one, set to expire in 60 days.
      def exchange_access_token(access_token, options = {})
        if info = exchange_access_token_info(access_token, options)
          info["access_token"]
        end
      end

      # Parses a signed request string provided by Facebook to canvas apps or in a secure cookie.
      #
      # @param input the signed request from Facebook
      #
      # @raise OAuthSignatureError if the signature is incomplete, invalid, or using an unsupported algorithm
      #
      # @return a hash of the validated request information
      def parse_signed_request(input)
        encoded_sig, encoded_envelope = input.split('.', 2)
        raise OAuthSignatureError, 'Invalid (incomplete) signature data' unless encoded_sig && encoded_envelope

        signature = base64_url_decode(encoded_sig).unpack("H*").first
        envelope = JSON.parse(base64_url_decode(encoded_envelope))

        raise OAuthSignatureError, "Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'

        # now see if the signature is valid (digest, key, data)
        hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, @app_secret, encoded_envelope)
        raise OAuthSignatureError, 'Invalid signature' if (signature != hmac)

        envelope
      end

      protected

      def get_token_from_server(args, post = false, options = {})
        # fetch the result from Facebook's servers
        response = fetch_token_string(args, post, "access_token", options)

View on GitHub (pinned to 47d052063e)

Solutions

  1. Pass the untouched value of cookies["fbsr_#{@app_id}"] or the raw signed_request parameter straight to the parser; do not pre-decode, strip, or re-encode it.
  2. Validate the shape before parsing: the value must match the pattern of base64url characters joined by exactly one dot.
  3. Log the offending value (length and prefix) to find where it gets mangled in transit.
  4. Rescue Koala::Facebook::OAuthSignatureError in the login flow and treat the session as anonymous.

Example fix

// before
auth = @oauth.parse_signed_request(params[:signed_request])

// after
raw = params[:signed_request].to_s
if raw =~ /\A[\w\-]+\.[\w\-]+\z/
  auth = @oauth.parse_signed_request(raw)
else
  auth = nil # malformed payload: treat as signed out
end
Defensive patterns

Strategy: validation

Validate before calling

cookie = cookies["fbsr_#{APP_ID}"]
head :unauthorized unless cookie.is_a?(String) && cookie =~ /\A[\w\-]+\.[\w\-]+\z/

Type guard

def plausible_signed_request?(input)
  input.is_a?(String) && !input.empty? && input.match?("\A[\w\-]+\.[\w\-]+\z")
end

Try / catch

begin
  data = @oauth.parse_signed_request(raw)
rescue Koala::Facebook::OAuthSignatureError
  render json: { error: "invalid signed_request" }, status: :unauthorized
end

Prevention

When it happens

Trigger: Passing a string without a dot separator to parse_signed_request or get_user_info_from_cookies: a truncated fbsr_<app_id> cookie (proxy mangling or cookie-size limits), the wrong cookie value (for example the unsigned fbs_ cookie), a signed_request that was URL-decoded or otherwise altered in transit, or a test fixture that is not a real signature.envelope pair. Nil input raises NoMethodError instead; this error specifically means a non-empty string missing the dot.

Common situations: Cookie values truncated between browser and app; passing the whole cookie hash instead of the fbsr_ value; double URL-encoding when relaying signed_request through internal routes; recorded fixtures that predate a Facebook format change; monitoring that groups this with tampering attempts when it is usually client-side corruption.

Related errors


AI-assisted analysis of arsduo/koala@47d052063e (2026-08-23). Data as JSON: /api/errors/9a05366f4d4e4367. Report an issue: GitHub.