Troubleshooting
Solutions for common problems with approvals, authentication, integrations, and the API.
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_secondsvalue. - 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-Emailheader 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
Bearerprefix 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:
# Correct format
curl -H "Authorization: Bearer sa_live_abc123..."
# Common mistakes:
# Missing "Bearer " prefix
# Extra newline: "sa_live_abc123...\n"
# Wrong key type429 Too Many Requests
Symptoms: API calls return 429 with a retry_after value.
Solutions:
- Check the
X-RateLimit-Remainingheader 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-Resettimestamp before retrying.
Webhook not received
Solutions:
- Verify the
webhook_urlis 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_EMAILis 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.jsonto 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.