One OpenAI-compatible endpoint for all your AI workloads — with auth, policy, and cost control built in.
Point your apps and agents at uprox instead of OpenAI. Hand out revocable tokens instead of raw provider keys, enforce per-service limits and budgets, and log every request.
![]() |
![]() |
Change two lines — the base URL and the key — and you're routing through uprox:
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: 'uprox_live_…', // a revocable machine token, not your real key
baseURL: 'http://localhost:5173/v1'
});
await client.chat.completions.create({
model: 'gpt-4o', // claude-* routes to Anthropic automatically
messages: [{ role: 'user', content: 'Hello' }]
});| Machine tokens | Revocable uprox_live_… tokens per service. Stored as a hash; shown once. |
| Multi-provider | OpenAI, Anthropic, and Azure OpenAI behind one endpoint, routed by model. |
| Policies | Limit which providers/models a service may call, plus per-token rate limits. |
| Budgets | Daily/monthly USD ceilings per service — over budget returns 402. |
| Response cache | Exact-match cache (streaming included) replays responses at zero cost. |
| Encrypted keys | Provider keys sealed with AES-256-GCM; never exposed to clients. |
| Audit log | Every request logged with status, cost, and latency. |
| Teams & SSO | Invite-only orgs and roles, with email/password or OIDC sign-in. |
Needs Node.js, pnpm, and Docker.
pnpm install
cp .env.example .env # fill in BETTER_AUTH_SECRET + ENCRYPTION_KEY
pnpm db:start # Postgres via docker
pnpm db:migrate
pnpm devOpen http://localhost:5173. On first run you'll land on a one-time /setup wizard to
create the administrator account (it becomes owner of the first organization). After that the
dashboard walks you through it: add a provider key → create a service → issue a token → make
your first request. New teammates join by invitation — see Authentication.
# generate ENCRYPTION_KEY
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
# or run the whole thing in Docker
docker build -t uprox . && docker run -p 3000:3000 --env-file .env uproxOpenAI-compatible gateway, authenticated with a Bearer uprox_live_… token (or
api-key: uprox_live_… for Azure-SDK clients):
| Endpoint | Notes |
|---|---|
POST /v1/chat/completions |
streaming supported |
POST /v1/responses |
OpenAI Responses API; streaming supported |
POST /v1/embeddings |
|
GET /v1/models |
aggregated from your configured providers |
/v1/files, /v1/files/{id}, /v1/files/{id}/content |
upload/list/retrieve/delete/download — used by SDKs that auto-upload image inputs |
The same gateway is reachable under URLs the Azure OpenAI SDK builds, so you can
point an existing Azure-style client at uprox by swapping its AZURE_OPENAI_ENDPOINT
for your uprox base URL and its AZURE_OPENAI_API_KEY for an uprox_live_… token.
| Endpoint | Equivalent of |
|---|---|
POST /openai/deployments/{deployment}/chat/completions |
legacy per-deployment Azure URL (model from URL) |
POST /openai/deployments/{deployment}/embeddings |
legacy per-deployment Azure URL |
POST /openai/deployments/{deployment}/responses |
legacy per-deployment Azure URL |
POST /openai/responses |
Responses API on Azure (model from body) |
POST /openai/chat/completions, POST /openai/embeddings |
Azure flat URLs (model from body) |
GET /openai/models |
Azure model listing |
POST /openai/v1/chat/completions (and /embeddings, …) |
newer Azure OpenAI v1 surface (api_version=preview) |
The api-version query string is accepted and ignored. Model routing is identical
to /v1/* — the deployment name acts as the model id, and uprox proxies to Azure
when your org has Azure credentials configured (Azure accepts arbitrary deployment
names; see provider settings).
Multiple Azure resources. A provider can hold several keys — add one per Azure
resource (each its own endpoint + key + label) on the Providers page. Each service
then pins which key it uses via the "Upstream key" picker; services left on
Automatic use the provider's highest-priority key. This lets you point different
services at different Azure resources (regions, quotas, subscriptions) without
changing any client code.
Everything else (services, tokens, providers, policies, audit) is managed in the dashboard or
via the session-authenticated REST API under /api.
- Machine tokens are opaque (
uprox_live_…) and stored only as a sha256 hash — like a password. The plaintext is shown once at creation; revoking one fails its services instantly. - Provider keys are encrypted at rest with AES-256-GCM; only the last 4 chars are kept for display, and the gateway swaps the token for the real key server-side — clients never see it.
uprox is invite-only. The first account is created once via the /setup wizard; everyone
else joins through an organization invitation (email or copy-able link) or via SSO. Sign-in
methods are configured with environment variables — no in-app toggles; set them and restart.
| Variable | Effect |
|---|---|
EMAIL_AUTH_DISABLED |
true hides email/password login, leaving SSO only. Default: email enabled. |
OIDC_ISSUER + OIDC_CLIENT_ID + OIDC_CLIENT_SECRET |
Set all three to enable a "Sign in with SSO" button (any OIDC provider). |
OIDC_PROVIDER_NAME |
Button label (default Single sign-on). |
OIDC_SCOPES |
Comma-separated scopes (default openid,email,profile). |
OIDC setup. Register uprox with your identity provider (Authentik, Keycloak, Entra ID, Auth0, …) using this redirect/callback URL:
{ORIGIN}/api/auth/oauth2/callback/oidc
then set the three OIDC_* vars and restart. OIDC users are auto-provisioned on first sign-in.
Note: keep email auth enabled until the first admin exists. If you disable it on an empty database the
/setupwizard can't create an account and you'll be locked out.
Every organization has three roles, backed by better-auth's organization plugin:
| Role | Can do |
|---|---|
| owner | everything, including org-level actions |
| admin | manage providers, policies, services, tokens, pricing, settings, members |
| member | read-only — unless an admin grants token/service permissions in Settings |
SvelteKit · TypeScript · Tailwind v4 + shadcn-svelte · better-auth · Postgres + Drizzle ORM · Node crypto
Scripts
| Command | Description |
|---|---|
pnpm dev / build / preview |
dev / production build / preview |
pnpm check |
typecheck |
pnpm test |
unit (Vitest) + E2E (Playwright) |
pnpm db:migrate / db:push / db:studio |
database |
pnpm auth:schema |
regenerate the better-auth schema |

