@qentrah/auth-sdk
v0.3.4
Published
Batteries-included Qentrah partner integration SDK for developers building OAuth, webhooks, resource calls, and consoles.
Downloads
352
Readme
@qentrah/auth-sdk
Batteries-included Qentrah partner integration SDK for developers building OAuth, webhooks, resource calls, and consoles.
These guides describe the published 0.3.2 package. The examples use the APIs and files in that release; beta packages should be kept on matching versions.
Documentation
- Install and verify
- Connect and refresh OAuth
- Call partner resources
- Verify webhooks
- Build an integration console
- API and exports
- Troubleshooting
Install and verify
Before you start
The package does not declare an engine requirement. Use a maintained Node.js release appropriate to your host application.
Use a project with a package.json. Check the runtime and package manager:
node --version
npm --versionInstall the documented version
npm install @qentrah/[email protected]Confirm the installation
npm ls @qentrah/auth-sdkThe output should show @qentrah/[email protected]. Commit the lockfile so another developer installs the same dependency tree.
Environment Variables
Use your own secret manager, hosting provider settings, or deployment environment.
QENTRAH_WORKSPACE_BASE_URL=https://app.qentrah.com
QENTRAH_PARTNER_CLIENT_ID=<your-partner-client-id>
QENTRAH_PARTNER_CLIENT_SECRET=<optional-confidential-client-secret>
QENTRAH_PARTNER_REDIRECT_URI=https://your-app.example.com/api/qentrah/oauth/callback
QENTRAH_PARTNER_SCOPES="organization:read client:read"
QENTRAH_WEBHOOK_SIGNING_SECRET=<your-webhook-signing-secret>QENTRAH_PARTNER_CLIENT_SECRET is only needed for confidential client setups. Never place it in browser-visible configuration.
You can normalize the public OAuth settings with:
import { qentrahPartnerAuthorityFromEnv } from "@qentrah/auth-sdk/partner";
const authority = qentrahPartnerAuthorityFromEnv({
QENTRAH_WORKSPACE_BASE_URL: process.env.QENTRAH_WORKSPACE_BASE_URL,
QENTRAH_PARTNER_CLIENT_ID: process.env.QENTRAH_PARTNER_CLIENT_ID,
QENTRAH_PARTNER_REDIRECT_URI: process.env.QENTRAH_PARTNER_REDIRECT_URI,
QENTRAH_PARTNER_SCOPES: process.env.QENTRAH_PARTNER_SCOPES,
});Browser Connect Button
<button id="qentrah-authorize">Authorize with Qentrah</button>import { mountQentrahAuthorizeButton } from "@qentrah/auth-sdk/partner/browser";
mountQentrahAuthorizeButton({
buttonId: "qentrah-authorize",
startUrl: "/api/qentrah/oauth/start",
label: "Authorize with Qentrah",
disabledLabel: "Opening...",
onError(error) {
reportConnectionError(error);
},
});The button should point at a backend route in your app. It should not receive tokens or secrets.
Expected result
The connect button opens your backend start route. It cannot complete authorization until you implement server-side state and token storage and register the callback URI.
Connect and refresh OAuth
Run this integration code on the server unless the example explicitly mounts a browser button. tokenVault, savePendingOAuthState, loadQentrahSession, and event callbacks are application integration points, not exports supplied by the SDK. Implement them with your storage and user-session model.
OAuth Routes
The Next.js helper is optional. Use it if your app uses Next route handlers.
// app/api/qentrah/oauth/config.ts
import { createQentrahPartnerAuthHandlers } from "@qentrah/auth-sdk/partner/next";
export const qentrahAuth = createQentrahPartnerAuthHandlers({
workspaceBaseUrl: process.env.QENTRAH_WORKSPACE_BASE_URL!,
clientId: process.env.QENTRAH_PARTNER_CLIENT_ID!,
clientSecret: process.env.QENTRAH_PARTNER_CLIENT_SECRET,
redirectUri: process.env.QENTRAH_PARTNER_REDIRECT_URI!,
scopes: ["organization:read", "client:read"],
sessionStore: {
async savePendingAuthorization({ pending, request }) {
await savePendingOAuthState(request, pending);
},
async loadPendingAuthorization({ state, request }) {
return loadPendingOAuthState(request, state);
},
async clearPendingAuthorization({ state, request }) {
await clearPendingOAuthState(request, state);
},
},
tokenStore: {
async saveTokens({ organizationId, tokenSet, scopes }) {
await tokenVault.save({
provider: "qentrah",
organizationId,
scopes,
tokenSet,
});
},
},
afterSuccessRedirect: "/settings/integrations/qentrah?connected=1",
afterErrorRedirect: "/settings/integrations/qentrah?error=1",
});// app/api/qentrah/oauth/start/route.ts
import { qentrahAuth } from "../config";
export const GET = qentrahAuth.start;// app/api/qentrah/oauth/callback/route.ts
import { qentrahAuth } from "../config";
export const GET = qentrahAuth.callback;For other backend frameworks, use the lower-level helpers from @qentrah/auth-sdk/partner and wire the generated redirect URL, pending state storage, callback validation, and token storage into your own routes.
Refresh Tokens
Refresh from server code, then save the returned token set back to your secure storage.
import { refreshQentrahPartnerAccessToken } from "@qentrah/auth-sdk/partner";
const tokenSet = await refreshQentrahPartnerAccessToken({
workspaceBaseUrl: process.env.QENTRAH_WORKSPACE_BASE_URL!,
clientId: process.env.QENTRAH_PARTNER_CLIENT_ID!,
clientSecret: process.env.QENTRAH_PARTNER_CLIENT_SECRET,
refreshToken: savedRefreshToken,
});
await tokenVault.save({ provider: "qentrah", tokenSet });Call partner resources
Run this integration code on the server unless the example explicitly mounts a browser button. tokenVault, savePendingOAuthState, loadQentrahSession, and event callbacks are application integration points, not exports supplied by the SDK. Implement them with your storage and user-session model.
Service-App Client
Use the service client from server code after your app has a saved access token.
import { createQentrahServiceAppClient } from "@qentrah/auth-sdk/partner/service-app";
const qentrah = createQentrahServiceAppClient({
workspaceBaseUrl: process.env.QENTRAH_WORKSPACE_BASE_URL!,
accessToken: savedAccessToken,
});
const organization = await qentrah.me();
const clients = await qentrah.listClients({
organizationId,
options: {
limit: 25,
search: "Acme",
status: "active",
},
});
const createdClient = await qentrah.createClient({
organizationId,
input: {
name: "Acme Buyer",
email: "[email protected]",
},
idempotencyKey: createIdempotencyKey(),
});
await qentrah.updateClient({
organizationId,
clientId: createdClient.id,
input: { name: "Acme Buyer Updated" },
});
await qentrah.deleteClient({
organizationId,
clientId: createdClient.id,
});Read helpers include:
melistClientslistPropertieslistProjectslistTaskslistCalendarlistMedialistWebhooks
Common options include limit, cursor, search, type, status, startAt, endAt, indexStart, and indexEnd. Media also supports resourceType and resourceId.
The older read, write, and sendWebhook helpers remain available for existing integrations.
Verify webhooks
Run this integration code on the server unless the example explicitly mounts a browser button. tokenVault, savePendingOAuthState, loadQentrahSession, and event callbacks are application integration points, not exports supplied by the SDK. Implement them with your storage and user-session model.
Webhook Verification
Use webhook helpers from server code. The signing secret must remain server-side.
// app/api/qentrah/webhooks/route.ts
import { createQentrahWebhookHandler } from "@qentrah/auth-sdk/partner/webhooks";
export const runtime = "nodejs";
export const POST = createQentrahWebhookHandler({
signingSecret: process.env.QENTRAH_WEBHOOK_SIGNING_SECRET!,
handlers: {
async "client.created"(event) {
await syncClientCreated(event.data);
},
async "client.updated"(event) {
await syncClientUpdated(event.data);
},
async "client.deleted"(event) {
await syncClientDeleted(event.data);
},
},
async onUnhandledEvent(event) {
await recordUnhandledEvent(event.type);
},
});Verify against the original request body before parsing JSON. The helper does that for standard Request objects.
Build an integration console
Run this integration code on the server unless the example explicitly mounts a browser button. tokenVault, savePendingOAuthState, loadQentrahSession, and event callbacks are application integration points, not exports supplied by the SDK. Implement them with your storage and user-session model.
Headless Integration Harness
The harness gives you reusable data models for a developer console without forcing a React component or a specific app layout.
import {
createQentrahPartnerConsoleService,
qentrahPartnerSections,
} from "@qentrah/auth-sdk/partner/harness";
const consoleService = createQentrahPartnerConsoleService({
workspaceBaseUrl: process.env.QENTRAH_WORKSPACE_BASE_URL!,
redirectUri: process.env.QENTRAH_PARTNER_REDIRECT_URI!,
requestedScopes: ["organization:read", "client:read", "client:create"],
session: await loadQentrahSession(userId),
});
const sections = consoleService.sections();
const lifecycle = consoleService.lifecycle();
const credentialSnapshot = consoleService.credentials();
const clientsQuery = consoleService.searchParams("clients", {
limit: 25,
search: "Acme",
status: "active",
});The harness can:
- Return the available console sections and the scopes each section needs.
- Detect missing scopes and reauthorization needs.
- Build OAuth lifecycle metadata for docs or UI.
- Build query parameters for list filters.
- Convert API responses into compact render rows.
- Normalize operation results for Test Results views.
- Sanitize nested payloads before rendering them.
Example rendering flow:
const result = await consoleService.runResourceOperation({
sectionId: "clients",
operation: "read",
resource: "client",
options: { limit: 25, search: "Acme" },
});
const rows = consoleService.renderRows("clients", result.responseSummary);
const safeResult = consoleService.result({
sectionId: "clients",
operation: "read",
method: "GET",
path: "/api/qentrah/clients",
status: result.status,
response: result.responseSummary,
error: result.error,
});Render rows, sections, lifecycle, credentialSnapshot, and safeResult with your own UI framework.
WordPress And Server-Backed Apps
For WordPress or PHP-backed products, keep the same separation of responsibilities:
- Enqueue the browser button script in the admin screen or integration settings page.
- Point the button at a server route that starts OAuth.
- Store pending OAuth state in a server-side session or database table.
- Complete the callback on the server and save token data in encrypted storage.
- Proxy Qentrah resource calls through server endpoints.
- Render only sanitized connection status, section readiness, request summaries, and result summaries in the admin UI.
If your WordPress plugin uses a Node service or build step, you can use this package directly in that server layer. If your backend is pure PHP, mirror the same OAuth, webhook, and storage contract server-side, and use the browser bundle only for the connect button.
API and exports
Package identity
| Field | Value |
| --- | --- |
| Package | @qentrah/auth-sdk |
| Version inspected | 0.3.2 |
| License | UNLICENSED |
| Module type | module |
Public import paths
| Import path | Published target |
| --- | --- |
| @qentrah/auth-sdk | ./dist/index.d.ts |
| @qentrah/auth-sdk/errors | ./dist/errors/index.d.ts |
| @qentrah/auth-sdk/partner | ./dist/partner/index.d.ts |
| @qentrah/auth-sdk/partner/browser | ./dist/partner/browser/index.d.ts |
| @qentrah/auth-sdk/partner/next | ./dist/partner/next/index.d.ts |
| @qentrah/auth-sdk/partner/service-app | ./dist/partner/service-app/index.d.ts |
| @qentrah/auth-sdk/partner/harness | ./dist/partner/harness/index.d.ts |
| @qentrah/auth-sdk/partner/webhooks | ./dist/partner/webhooks/index.d.ts |
| @qentrah/auth-sdk/qentrah-auth.js | ./dist/qentrah-auth.js |
| @qentrah/auth-sdk/package.json | ./package.json |
Exports
import {
buildQentrahPartnerAuthorizeUrl,
exchangeQentrahPartnerAuthorizationCode,
refreshQentrahPartnerAccessToken,
qentrahPartnerAuthorityFromEnv,
} from "@qentrah/auth-sdk/partner";
import { mountQentrahAuthorizeButton } from "@qentrah/auth-sdk/partner/browser";
import { createQentrahPartnerAuthHandlers } from "@qentrah/auth-sdk/partner/next";
import { createQentrahServiceAppClient } from "@qentrah/auth-sdk/partner/service-app";
import { createQentrahWebhookHandler, verifyQentrahWebhook } from "@qentrah/auth-sdk/partner/webhooks";
import {
createQentrahPartnerConsoleService,
qentrahPartnerSections,
sanitizeQentrahPartnerPayload,
} from "@qentrah/auth-sdk/partner/harness";The browser bundle is also available as:
<script src="/qentrah-auth.js"></script>It exposes:
window.QentrahAuth.mountAuthorizeButton(...)Inspect the original release
Open the versioned npm page or download its published archive. The archive includes the actual executable files and declarations used to write these guides.
Troubleshooting
Check the installed version
npm ls @qentrah/auth-sdkCompare the installed version with the version noted in this guide. Inspect your lockfile before changing dependencies; prerelease behavior may differ between versions.
Import or module errors
Use only public import paths listed in API and exports. Avoid importing guessed paths inside dist. ESM-only packages require an ESM-aware application. Install declared peer dependencies in the consuming application.
Error Handling
SDK errors are stable enough to branch on:
CONFIGURATION_ERRORAUTHORIZATION_DENIEDINVALID_STATETOKEN_EXCHANGE_FAILEDORGANIZATION_AUTHORIZATION_MISSINGMISSING_RAW_BODYSTALE_TIMESTAMPINVALID_SIGNATUREUNSUPPORTED_RUNTIME
import { isQentrahPartnerAuthError } from "@qentrah/auth-sdk/partner";
try {
await connectQentrah();
} catch (error) {
if (isQentrahPartnerAuthError(error)) {
await recordIntegrationIssue({
code: error.code,
message: error.message,
});
}
}Security Rules
Keep sensitive values out of browser code, public logs, screenshots, client bundles, docs, and version control.
- Browser code should only redirect to your backend start route.
- Exchange authorization codes on the server.
- Store access tokens, refresh tokens, client secrets, webhook signing secrets, and authorization codes in your own secure server storage.
- Verify webhook signatures before trusting event data.
- Render only sanitized credential and result snapshots in admin UI.
- Use placeholders in examples, docs, and tests.
Callback failures
For INVALID_STATE, check that the same user session loads the saved pending state and that state is cleared after use. For token exchange failures, check the registered redirect URI, client configuration, and authority URL. Store refreshed tokens atomically and never send the stored token set to a browser.
Release documentation
Documentation checked against the previously published package artifact. This documentation-only release preserves executable files and dependencies.
