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
- 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.
- Validate the shape before parsing: the value must match the pattern of base64url characters joined by exactly one dot.
- Log the offending value (length and prefix) to find where it gets mangled in transit.
- 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
- Hand the raw fbsr_ cookie value to get_user_info_from_cookies; never split or decode it yourself
- Reject mangled payloads at the routing layer with a shape constraint before they reach auth code
- Keep the cookie jar small enough that the fbsr_ cookie is never dropped or truncated
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
- Unsupported algorithm #{envelope['algorithm']}
- Invalid signature
- Koala::Utils.logger.warn("Signed cookie didn't contain Faceb
- generate_client_code received an error: empty response body
- ServerError.new(response.status, response.body)
AI-assisted analysis of arsduo/koala@47d052063e (2026-08-23).
Data as JSON: /api/errors/9a05366f4d4e4367.
Report an issue: GitHub.