Troubleshooting

Solutions for common problems with approvals, authentication, integrations, and the API.

Key Concepts

This page covers the most common issues encountered when using SignedApproval. Each issue includes the symptoms, cause, and solution. If your problem is not listed here, contact support at support@signedapproval.net.

Authentication Issues

Passkey registration fails

Symptoms: The WebAuthn ceremony starts but fails with an error, or the browser prompt never appears.

Causes & Solutions:

  • Ensure you are on signedapproval.net (not localhost or a different domain). Passkeys are bound to the RP ID.
  • Use a supported browser (Chrome, Safari, Edge, Firefox). Ensure the browser is up to date.
  • If using a hardware security key, insert it before clicking Register. Ensure drivers are installed.
  • WebAuthn challenges expire after 5 minutes. If the ceremony takes too long, start over.
  • Check that your browser allows WebAuthn (Settings → Privacy → Security keys).

TOTP code is "invalid" but looks correct

Symptoms: You enter the 6-digit code from your authenticator app but get "Invalid code".

Causes & Solutions:

  • Clock drift -- Your phone's time may be slightly off. Enable automatic time setting (Settings → General → Date & Time → Set Automatically).
  • Wrong account -- If you have multiple TOTP entries, ensure you are reading the code for "SignedApproval".
  • Code expired -- TOTP codes rotate every 30 seconds. Wait for a fresh code if the current one is about to expire.

Face ID does not work in the iOS app

Symptoms: Tapping Approve does not trigger Face ID, or Face ID fails repeatedly.

Causes & Solutions:

  • Check iOS Settings → SignedApproval → Face ID is enabled.
  • Ensure Face ID works with other apps. If it does not, reconfigure Face ID in iOS Settings → Face ID & Passcode.
  • After multiple Face ID failures, iOS falls back to passcode. This is expected and still counts as biometric auth.

Approval Issues

Request expires before I can approve

Symptoms: By the time you see the notification and open the app, the request has already expired.

Solutions:

  • Ask the caller to use a longer ttl_seconds value.
  • Set a higher default TTL in Settings → Preferences.
  • Enable push notifications and keep your phone charged so you are alerted immediately.
  • Check if quiet hours are suppressing notifications when requests are arriving.

No pending requests visible

Symptoms: The dashboard or iOS app shows no pending requests, but you expect one.

Solutions:

  • Ensure you are signed in with the correct Google account. The request is routed to a specific approver email.
  • The request may have already expired. Check the History tab.
  • Pull to refresh in the iOS app, or reload the dashboard page.
  • If using internal service tokens, verify the X-Approver-Email header matches your signed-in email.

Signature verification returns "invalid"

Symptoms: The /verify endpoint returns valid: false.

Solutions:

  • If doing offline verification, ensure the payload JSON uses alphabetical key ordering.
  • Check that you are using the correct public key (from the same response or the same approver).
  • Ensure you are verifying the correct request ID.
  • If the request is still "pending", there is no decision to verify yet.

API Issues

401 Unauthorized -- "Invalid API key"

Causes:

  • The API key was revoked or never existed.
  • Missing Bearer prefix in the Authorization header.
  • Extra whitespace or newline characters in the key (common with environment variables).
  • Using the wrong key format (e.g., a Supabase anon key instead of an sa_live_ key).

Fix: Create a fresh API key in the dashboard and ensure it is passed correctly:

bash
# Correct format
curl -H "Authorization: Bearer sa_live_abc123..."

# Common mistakes:
# Missing "Bearer " prefix
# Extra newline: "sa_live_abc123...\n"
# Wrong key type

429 Too Many Requests

Symptoms: API calls return 429 with a retry_after value.

Solutions:

  • Check the X-RateLimit-Remaining header to monitor your usage.
  • Reduce polling frequency when checking status (3-5 second intervals are recommended).
  • Use webhooks instead of polling for real-time notifications.
  • Wait until the X-RateLimit-Reset timestamp before retrying.

Webhook not received

Solutions:

  • Verify the webhook_url is correct and uses HTTPS.
  • Ensure your endpoint returns a 2xx status code within 10 seconds.
  • Check your server's firewall allows incoming POST requests from SignedApproval's servers.
  • Test with a webhook inspection tool like webhook.site to confirm the payload format.

Integration Issues

GitHub commit status not appearing

Solutions:

  • Ensure the SignedApproval GitHub App is installed on the repository.
  • Check that the PR's target branch matches your configured branch patterns.
  • Verify the GitHub App has the required permissions (commit statuses: read/write, pull requests: read).
  • Check the repository configuration in Dashboard → Settings → Integrations → GitHub.

MCP server bootstrap fails

Solutions:

  • Verify SIGNEDAPPROVAL_EMAIL is set correctly in your MCP config.
  • Ensure you have a SignedApproval account with that email (create one at signedapproval.net).
  • Check the bootstrap rate limit (5 per hour per email). Wait and try again.
  • Look for the consent request in your dashboard or iOS app and approve it.
  • Delete ~/.signedapproval/config.json to force a fresh bootstrap.

iOS app shows "Network Error"

Solutions:

  • Check your internet connection (Wi-Fi or cellular).
  • The API at signedapproval.net may be temporarily unavailable. Try again in a few minutes.
  • In Release builds, certificate pinning is enforced. If the TLS certificate has changed, update the app.
  • Force-quit and reopen the app to reset the network session.
Note
If your issue is not covered here, reach out to support@signedapproval.net. Include your request ID, the error message, and the timestamp when the issue occurred.