OAuth PKCE
Let users authorize your app to use their EUrouter account and credits via OAuth PKCE.
OAuth PKCE (Proof Key for Code Exchange) lets third-party apps request API keys on behalf of EUrouter users. When a user authorizes your app, you receive an API key linked to their account. The user pays for their own usage with their credits.
How it works
- Your app generates a PKCE pair (a random
code_verifierand its SHA-256 hash) - Your app redirects the user to EUrouter with the code challenge
- The user sees a consent screen and approves access
- EUrouter redirects back to your app with an authorization code
- Your app exchanges the code and verifier for an API key
- You use the key for API calls, billed to the user's credits
Quick start
This end-to-end example shows the full flow in JavaScript (Node.js):
import { randomBytes, createHash } from "crypto";
// 1. Generate PKCE pair
const codeVerifier = randomBytes(32).toString("base64url");
const codeChallenge = createHash("sha256")
.update(codeVerifier)
.digest("base64url");
// 2. Redirect user to EUrouter (in your web app)
const authUrl = new URL("https://api.eurouter.ai/api/v1/auth");
authUrl.searchParams.set("callback_url", "https://your-app.com/callback");
authUrl.searchParams.set("code_challenge", codeChallenge);
authUrl.searchParams.set("code_challenge_method", "S256");
// redirect user to authUrl.toString()
// 3. On your /callback endpoint, extract the code
const code = new URL(request.url).searchParams.get("code");
// 4. Exchange code for API key (server-side)
const response = await fetch("https://api.eurouter.ai/api/v1/auth/keys", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
code,
code_verifier: codeVerifier,
code_challenge_method: "S256",
}),
});
const { key, user_id } = await response.json();
// Store the key securely — it's shown only onceStep-by-step guide
Step 1: Generate PKCE credentials
Create a code_verifier (a random string, 43-128 characters) and derive a code_challenge by hashing it with SHA-256.
JavaScript (Node.js)
import { randomBytes, createHash } from "crypto";
const codeVerifier = randomBytes(32).toString("base64url");
const codeChallenge = createHash("sha256")
.update(codeVerifier)
.digest("base64url");
// Store codeVerifier securely on your server — you'll need it in Step 4Python
import secrets
import hashlib
import base64
code_verifier = secrets.token_urlsafe(32)
code_challenge = (
base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
)
.decode()
.rstrip("=")
)Step 2: Redirect user to EUrouter
Send the user's browser to the authorization endpoint with your PKCE challenge:
https://api.eurouter.ai/api/v1/auth
?callback_url=https://your-app.com/callback
&code_challenge={code_challenge}
&code_challenge_method=S256| Parameter | Required | Description |
|---|---|---|
callback_url | Yes | Where to redirect after authorization. Must be HTTPS (HTTP allowed for localhost during development). |
code_challenge | Yes | Base64url-encoded SHA-256 hash of the code verifier (43-128 characters). |
code_challenge_method | No | S256 (default, recommended) or plain. |
The user will see a consent screen showing your app's domain and what access is being requested.
Step 3: Receive the authorization code
After the user approves, they're redirected to your callback URL with a code parameter:
https://your-app.com/callback?code=abc123...If the user denies the request:
https://your-app.com/callback?error=access_deniedStep 4: Exchange code for API key
Make a server-side POST request to exchange the authorization code for an API key:
curl -X POST https://api.eurouter.ai/api/v1/auth/keys \
-H "Content-Type: application/json" \
-d '{
"code": "abc123...",
"code_verifier": "your_original_verifier",
"code_challenge_method": "S256"
}'| Field | Required | Description |
|---|---|---|
code | Yes | The authorization code received on the callback URL. |
code_verifier | Yes | The original random string used to generate the code challenge (43-128 characters). |
code_challenge_method | Yes | Must match the method used in Step 2 (S256 or plain). |
Response (200):
{
"key": "eur_abc123.secretxyz",
"user_id": "e1faa70b-..."
}The key is shown only once. Store it securely.
Step 5: Use the API key
The returned key works like any other EUrouter API key:
curl https://api.eurouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer eur_abc123.secretxyz" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.1",
"messages": [{"role": "user", "content": "Hello!"}]
}'API usage is billed to the authorizing user's credits.
Python example
Full flow in Python:
import secrets
import hashlib
import base64
import requests
# Step 1: Generate PKCE pair
code_verifier = secrets.token_urlsafe(32)
code_challenge = (
base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
)
.decode()
.rstrip("=")
)
# Step 2: Build auth URL and redirect user
auth_url = (
f"https://api.eurouter.ai/api/v1/auth"
f"?callback_url=https://your-app.com/callback"
f"&code_challenge={code_challenge}"
f"&code_challenge_method=S256"
)
# Step 3: After user approves, extract code from callback URL
# Step 4: Exchange code for API key
resp = requests.post(
"https://api.eurouter.ai/api/v1/auth/keys",
json={
"code": code,
"code_verifier": code_verifier,
"code_challenge_method": "S256",
},
)
data = resp.json()
api_key = data["key"]
user_id = data["user_id"]Consent screen
When a user is redirected to EUrouter, they see a consent screen that shows:
- Your app's domain and a clear description of what's being requested
- Permissions being granted: an API key linked to their account that uses their credits
- Where they'll be redirected after authorizing
- Deny and Authorize buttons
Users must be signed in to their EUrouter account to authorize. If they're not signed in, they'll be prompted to sign in first.
Error reference
| Status | When | Message |
|---|---|---|
400 | code_challenge_method at exchange doesn't match what was used at authorization | Invalid code_challenge_method |
403 | Code is invalid, expired, already used, or the PKCE verifier is wrong | Invalid code or code_verifier |
405 | Wrong HTTP method (e.g., GET instead of POST on the exchange endpoint) | Method Not Allowed |
Security notes
- Use S256 rather than
plainfor the code challenge method. Only useplainin environments that genuinely cannot compute SHA-256. - HTTPS required for all callback URLs in production.
http://localhostis allowed during development. - Authorization codes expire after 10 minutes and are single-use. If the exchange fails, you must start the flow over.
- Store the code verifier on your server, never expose it in client-side code.
- The API key is shown only once in the exchange response. If you lose it, the user must go through the authorization flow again.