Service tokens
Tefily service tokens (kfxs_…) are machine credentials owned by a project. They call the data API (/api/p/:projectId/*) and POST /auth/verify. They cannot call console APIs (/api/organizations, schema admin, hosting, …).
They bypass end-user access rules, like a platform token on the data API.
Create them in the console (Developers / service tokens), with the admin SDK projects.createServiceToken, or via MCP (create_service_token). The secret is returned once. The mint call is on the admin page.
The constructor writes the token onto the HTTP client’s bearer before any call. It is not a separate header argument. setToken (JavaScript and Dart) and set_token (Python) do the same thing later. auth.verify then POSTs /api/p/<projectId>/auth/verify with that bearer and body { "token": "<project user jwt>" }.
login on this client replaces kfxs_… with a project JWT. Keep a separate client for the service token, and do not call login on it. A kfx_… personal access token is a different credential: it is not a service token, and it is not what auth.verify sends as the bearer in the samples below.
There is no admin client in JavaScript or Python. These samples are the data-API clients.
When to use them
Section titled “When to use them”- Password reset, webhooks, and other server routes that read or write collections
- Verifying a project JWT your frontend sent you
- Scripts that must not use a human PAT
Do not put kfxs_… in Expo public env, Vite VITE_* that ships to the browser, or a mobile binary.
JavaScript
Section titled “JavaScript”KataflaxClient accepts serviceToken. auth.verify(token) returns { valid: boolean, user?: Record<string, unknown> }. Await it.
const backend = new KataflaxClient({ baseUrl: 'https://api.tefily.com', projectId: 'YOUR_PROJECT_ID', serviceToken: process.env.TEFILY_SERVICE_TOKEN!,});
const checked = await backend.auth.verify(incomingUserJwt);if (!checked.valid) { throw new Error('Invalid session');}
await backend.collection('password_resets').create({ email, tokenHash: hash,});auth.verify(token) returns ({bool valid, Map<String, dynamic>? user}). Platform is from dart:io.
final backend = KataflaxClient( baseUrl: 'https://api.tefily.com', projectId: 'YOUR_PROJECT_ID', serviceToken: Platform.environment['TEFILY_SERVICE_TOKEN']!,);
final checked = await backend.auth.verify(incomingUserJwt);if (!checked.valid) { throw Unauthorized();}
await backend.collection('password_resets').create({ 'email': email, 'tokenHash': hash,});Python
Section titled “Python”auth.verify(token) returns VerifyResult (valid, user), exported from kataflax. The call is synchronous.
import osfrom kataflax import KataflaxClient
backend = KataflaxClient( base_url="https://api.tefily.com", project_id="YOUR_PROJECT_ID", service_token=os.environ["TEFILY_SERVICE_TOKEN"],)
checked = backend.auth.verify(incoming_user_jwt)if not checked.valid: raise PermissionError("Invalid session")
backend.collection("password_resets").create({ "email": email, "tokenHash": hash,})REST verify
Section titled “REST verify”POST /api/p/{projectId}/auth/verifyAuthorization: Bearer kfxs_…Content-Type: application/json
{"token":"<project user jwt>"}Response: { "success": true, "data": { "valid": true, "user": { ... } } } (shape may wrap valid / user in data).