Qeet Docs

Quickstart

Install an SDK, initialize it with an API key, and protect a route — verifying user sessions against the public JWKS.

This guide gets you from zero to a protected route. You'll create an API key, initialize a server SDK, and verify an incoming user access token locally against Qeet ID's published ES256 JWKS — no network round-trip per request.

Two integration styles: a server SDK (TypeScript/Go/Python) that verifies tokens and manages users, and the @qeetid/nextjs + @qeetid/react pair that runs the full hosted-login OAuth flow for you. This page covers the server SDK; for the drop-in web flow jump to SDKs → Next.js.

1. Create an API key

API keys authenticate your backend to the Qeet ID API. Create one in the admin dashboard, or via the API with an admin token:

POST/v1/api-keysCreate an API key
terminal
curl -X POST https://api.qeetid.com/v1/api-keys \
  -H "Authorization: Bearer $QEETID_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"backend"}'

The response includes the secret once — a qk_… value. Store it as a server secret; never ship it to a browser.

API keys are server-only

A qk_… key has tenant-scoped access to the API. Keep it in an environment variable or secret manager. For the browser, use the hosted-login flow (@qeetid/nextjs) — the secret stays on the server.

2. Install a server SDK

Bash
pnpm add @qeetid/sdk
Bash
go get github.com/qeetgroup/qeetid-go
Bash
pip install qeetid

3. Initialize the client

The API key goes in via the SDK config — the SDK sends it as Authorization: ApiKey qk_… on every request.

lib/qeetid.ts
TypeScript
import { Qeetid } from "@qeetid/sdk";

export const qeetid = new Qeetid({
  apiKey: process.env.QEETID_API_KEY!, // qk_…
  // baseUrl defaults to https://api.qeetid.com
});
qeetid.go
import (
  "os"
  qeetidsdk "github.com/qeetgroup/qeetid-go"
)

var qeetid = qeetidsdk.New(qeetidsdk.Options{
  APIKey: os.Getenv("QEETID_API_KEY"), // qk_…
})
qeetid_client.py
Python
import os
from qeetid import Qeetid

qeetid = Qeetid(api_key=os.environ["QEETID_API_KEY"])  # qk_…

4. Verify a session

Your app receives a user access token (an ES256 JWT) — typically as a bearer header from your frontend. Verify it locally: the SDK checks the signature against the cached JWKS, then expiry, issuer, and audience. No per-request network call.

TypeScript
const claims = await qeetid.sessions.verify(accessToken);
// claims.userId, claims.tenantId, claims.sessionId
claims, err := qeetid.Sessions.Verify(ctx, accessToken)
// claims.UserID, claims.TenantID
Python
claims = qeetid.sessions.verify(access_token)
# claims.user_id, claims.tenant_id

Local verification scales

Because tokens are ES256 (asymmetric) and the JWKS is public, your services verify tokens offline after a one-time key fetch. Rotating signing keys publishes a new kid; the SDKs refetch automatically. See Sessions.

5. Protect a route

Combine verification with an authorization check. qeetid.can(...) is a single call to GET /v1/check.

app/api/billing/route.ts
TypeScript
import { qeetid } from "@/lib/qeetid";

export async function POST(req: Request) {
  const token = req.headers.get("authorization")?.replace("Bearer ", "");
  if (!token) return new Response("Unauthorized", { status: 401 });

  const claims = await qeetid.sessions.verify(token);

  const ok = await qeetid.can({
    user: claims.userId,
    tenant: claims.tenantId!,
    permission: "billing:write",
  });
  if (!ok) return new Response("Forbidden", { status: 403 });

  // … do the work
  return Response.json({ ok: true });
}
handler.go
Go
claims, err := qeetid.Sessions.Verify(ctx, token)
if err != nil {
  http.Error(w, "unauthorized", http.StatusUnauthorized)
  return
}

ok, err := qeetid.Can(ctx, qeetidsdk.PermissionCheck{
  User:       claims.UserID,
  Tenant:     claims.TenantID,
  Permission: "billing:write",
})
if err != nil || !ok {
  http.Error(w, "forbidden", http.StatusForbidden)
  return
}
views.py
Python
claims = qeetid.sessions.verify(token)

if not qeetid.can(user=claims.user_id, tenant=claims.tenant_id, permission="billing:write"):
    return Response(status=403)

Prefer a full web flow?

If you're building a Next.js app, @qeetid/nextjs runs the entire hosted-login OAuth flow (Authorization Code + PKCE), stores an encrypted HttpOnly session cookie, and silently refreshes near-expiry sessions in middleware — no token handling in your code. Pair it with @qeetid/react for <SignedIn> / <SignedOut> and useUser().

middleware.ts
TypeScript
import { qeetidMiddleware } from "@qeetid/nextjs/middleware";

export default qeetidMiddleware({ publicRoutes: ["/", "/pricing"] });

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

See SDKs → TypeScript & Next.js for the complete setup.

Next steps

On this page