Skip to main content
Four steps: generate a verifier, open a deep link, catch the one-time code, trade it for a token over localhost. TablePro releases the token only to the caller that can produce the verifier, so an app that intercepts the redirect holds a code it cannot spend. Nothing about this is Raycast-specific. Any client that can receive a callback, through its own URL scheme or a loopback HTTP listener, can pair.

Sequence

TablePro sheet asking to approve a pairing request with scope, connection, and expiry pickers

The pairing approval sheet

The whole client, in one file

Three constraints decide whether TablePro accepts the request at all:
  • The verifier is 43 to 128 characters from A-Z a-z 0-9 - . _ ~. 32 random bytes in base64url is 43.
  • The challenge is its base64url SHA-256, so exactly 43 base64url characters.
  • The redirect is a loopback http or https URL (127.0.0.1, localhost, ::1), or a private-use scheme an installed app has registered. Anything else, or one carrying credentials, is refused with “The redirect address is not a local callback, so pairing was refused.”
One delivery detail: a raycast:// redirect gets the code wrapped as ?context={"code":"<uuid>"}, Raycast’s launch-context convention, and every other scheme gets a flat ?code=<uuid>. The exchange endpoint takes no bearer token: the single-use code plus the verifier is the credential. It and /mcp are the only paths the server serves, and both accept POST only.

What the user approves

The sheet names the client and counts down the five minutes the request is good for, dimming Approve when it runs out. Three controls sit under that: Permission Level (starting at what the link asked for, movable in either direction), Allowed Connections (all, or a checked subset), and Expiration (never, 1, 7, 30 or 90 days). The link’s parameters are a request, not a grant. Approving mints the token, holds the plaintext against a one-time code for 5 minutes, and opens the redirect. Pairing again mints a second token rather than replacing the first, so an extension that re-pairs should stop using its old one. Revoke either under Settings > Integrations > Authentication.

Security properties

Errors

A failed verification burns the code, so retrying with a guessed verifier is not an option: start a new pair request. Every failed exchange lands in the activity log under the auth category with outcome denied. Clicking Deny opens the redirect with error=denied and error_description=user_denied, wrapped in the context JSON for raycast:// and appended as flat parameters otherwise.