EUrouter

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

  1. Your app generates a PKCE pair (a random code_verifier and its SHA-256 hash)
  2. Your app redirects the user to EUrouter with the code challenge
  3. The user sees a consent screen and approves access
  4. EUrouter redirects back to your app with an authorization code
  5. Your app exchanges the code and verifier for an API key
  6. 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 once

Step-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 4

Python

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
ParameterRequiredDescription
callback_urlYesWhere to redirect after authorization. Must be HTTPS (HTTP allowed for localhost during development).
code_challengeYesBase64url-encoded SHA-256 hash of the code verifier (43-128 characters).
code_challenge_methodNoS256 (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_denied

Step 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"
  }'
FieldRequiredDescription
codeYesThe authorization code received on the callback URL.
code_verifierYesThe original random string used to generate the code challenge (43-128 characters).
code_challenge_methodYesMust 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"]

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

StatusWhenMessage
400code_challenge_method at exchange doesn't match what was used at authorizationInvalid code_challenge_method
403Code is invalid, expired, already used, or the PKCE verifier is wrongInvalid code or code_verifier
405Wrong HTTP method (e.g., GET instead of POST on the exchange endpoint)Method Not Allowed

Security notes

  • Use S256 rather than plain for the code challenge method. Only use plain in environments that genuinely cannot compute SHA-256.
  • HTTPS required for all callback URLs in production. http://localhost is 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.

FAQ


On this page

Claim €15 free credits·300 left
Sign up free →