Console
Authentication

OAuth PKCE: let users connect your app

Let an app get a key from a signed-in member.

Your app can get a RouterPlus inference key for a user. The user does not copy a key. The user signs in, selects a workspace and approves. Then your app receives the key.

The flow is OAuth 2.0 with PKCE (RFC 7636). It uses the common request and response shapes for PKCE key exchange. To use an existing PKCE client, change its two URLs.

Steps

  1. 01
    Make a code verifier: 43 to 128 random characters from A-Z a-z 0-9 - . _ ~. Keep it in your app.
  2. 02
    Make the code challenge: base64url(sha256(verifier)), with no padding.
  3. 03
    Send the user's browser to the consent page:
https://demo.routerplus.com/auth?callback_url=https://yourapp.example.com/callback&code_challenge=CHALLENGE&code_challenge_method=S256
  1. 04
    The user approves. The browser goes to your callback_url, with ?code=CODE added.
  2. 05
    From your app, exchange the code for a key:
bash
curl -s https://dev2-api.routerplus.com/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -d '{"code":"CODE","code_verifier":"VERIFIER","code_challenge_method":"S256"}'
json
{"key": "tm_vk_...", "user_id": "[email protected]"}
  1. 06
    Send the key as a Bearer token on inference calls: Authorization: Bearer tm_vk_....
ParameterRequiredMeaning
callback_urlyesWhere the browser returns with the code. https only, except plain http on localhost and 127.0.0.1. No user name, password or fragment. Its own query parameters are kept.
code_challengerecommendedThe PKCE challenge. Without it, the code alone is enough to get the key.
code_challenge_methodnoS256 (recommended) or plain. Default plain.
key_labelnoThe key's name on the user's API keys page, up to 80 characters. Default: your callback host.
limitnoA spending limit for the key in USD, for example 25. The user can change it before approval.

The user sees your callback host, the workspace list and the limit. Owners and admins can approve. Viewers cannot approve. A user who is not signed in signs in first and then returns to the consent page.

Exchange endpoint

POST https://demo-api.routerplus.com/api/v1/auth/keys (also POST /v1/auth/keys)

Request body, JSON:

FieldRequiredMeaning
codeyesThe code from the callback.
code_verifierwhen a challenge was sentThe verifier you made in step 1.
code_challenge_methodnoIf sent, it must equal the method on the consent request.

Response 200: {"key": "...", "user_id": "<email of the user who approved>"}. RouterPlus returns the key one time. Store it in your app.

Rules

  • A code expires 10 minutes after approval.
  • A code works one time. A second exchange of the same code fails and makes no key.
  • A wrong code_verifier fails and leaves the code usable until it expires.
  • The key belongs to the workspace that the user selected. Its spend goes to that organization, up to the limit.
  • The user can disable the key at any time in the console, under Access > API keys.
  • If the user stops being an owner or admin before the exchange, the exchange fails. The code is then used up.

Errors

Errors have the shape {"error": {"code": <status>, "message": "..."}}.

StatusCause
400No code; the code is unknown, expired or used; or code_challenge_method is not S256 or plain, or differs from the consent request.
403The code_verifier does not match the challenge, or the user or workspace can no longer make keys.
405The method is not POST.
503A temporary failure. Retry with the same code.

For agents: /docs/oauth.md and /llms.txt