Sign in with Rapid Router
An OAuth PKCE flow so your users pay for your app with their own credits.
Let your users pay for your app's inference with their own Rapid Router credits, no key copy-pasting. An OAuth PKCE flow: you send the user to our consent page, they approve, and you exchange the returned code for an API key bound to their account. The key is a normal runtime key, visible in their dashboard and revocable by them at any time.
- Generate a random
code_verifier, hash it to acode_challenge(S256), and send the browser tohttps://rapidrouter.ai/oauth/authorize. - The user signs in if needed and approves. The browser lands back on your
callback_urlwith?code=...(or?error=access_deniedif they refuse). - POST the code and your verifier to
/api/v1/auth/keys. No session or auth header needed: the code plus the matching verifier is the proof. The response carries the key secret, shown exactly once.
callback_url must be https, or http://localhost (any port) for local development; anything else is rejected before the consent screen renders. Codes expire after 10 minutes and are single-use: a second exchange of the same code answers 400 code_consumed, a stale one 400 code_expired, and a wrong verifier 400 verifier_mismatch. The exchange endpoint is limited to 10 attempts a minute per IP. Keys created this way are named OAuth: <app name> in the user's dashboard, and revoking one there cuts your app off immediately.
// 1. verifier + challenge with WebCrypto, then redirect
const bytes = crypto.getRandomValues(new Uint8Array(32))
const verifier = btoa(String.fromCharCode(...bytes))
.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")
sessionStorage.setItem("rr_verifier", verifier)
const digest = await crypto.subtle.digest("SHA-256",
new TextEncoder().encode(verifier))
const challenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "")
location.href = "https://rapidrouter.ai/oauth/authorize?"
+ new URLSearchParams({
callback_url: "https://yourapp.com/callback",
code_challenge: challenge,
code_challenge_method: "S256",
app_name: "Your App",
})