Skip to main content

Authentication

SDK@techwriter/sdk-core Auth

Authentication

Every TechWriter API call must be authenticated. The platform supports four mechanisms — API keys, OAuth 2.0 Client Credentials, OAuth 2.0 Authorization Code, and signed JWT Bearer tokens — and the SDK speaks all four with a consistent surface.

For most server-side workloads an API key is enough. If you act on behalf of users, ship a public app, or need short-lived credentials with audit trails, use OAuth 2.0. Whatever you pick, send the credential in the Authorization: Bearer … header — the legacy X-API-KEY header is still accepted for compatibility but is no longer recommended.

All authenticated requests must travel over HTTPS. Plain HTTP and self-signed certificates are rejected at the edge — there are no exceptions, including for sandbox traffic.

Authentication methods

Pick the mechanism that matches who is making the call and how long you can hold a credential.

MethodBest forLifetimeNotes
API Key (Bearer)Server-to-server scripts, internal tooling, scheduled jobs.Until revokedLowest setup, highest blast radius if leaked.
OAuth 2.0 Client CredentialsBackend services that act on their own behalf.60 minutesShort-lived tokens limit exposure on leak.
OAuth 2.0 Authorization CodeApps that act on behalf of an end user (consent flow).60 minutes (refresh token: 30 days)Most secure for user-facing integrations.
JWT BearerFederated SSO and machine identities signed by your IdP.You set the exp claimStrong if your signing keys are protected.

API key types

The prefix tells you which environment a key targets. The SDK never mixes traffic across modes.

PrefixModeWhat it does
tw_test_…Test modeTargets the sandbox database. No real publishing happens and usage is not rate-limited or billed. Safe to check into version control for local development fixtures.
tw_live_…Live modeTargets production. Treat these like production database credentials — never commit, never ship in client code.
tw_restricted_…RestrictedLive key with a custom subset of scopes. Use these to give read-only dashboards or scoped automation just enough access.

Available scopes

Restricted keys and OAuth tokens carry one or more scopes. Keep them as narrow as possible — leak blast radius scales with what a credential can do.

ScopeGrants
articles:readList, retrieve, and search articles. No write access.
articles:writeCreate, update, publish, and archive articles.
templates:readBrowse the template library and folder hierarchy.
templates:writeCreate, edit, and delete templates and folders.
users:readList users, groups, and role assignments.
users:writeInvite users, edit profiles, assign roles and groups.
webhooks:manageSubscribe, verify, and rotate signing secrets for webhooks.
audit:readRead the immutable audit log for compliance reporting.

Token lifecycle

The SDK handles caching, refresh, and retries automatically. The table below describes what happens at each stage so you can reason about edge cases.

EventWhen it happensWhat to do
Token issuedOn login, OAuth exchange, or API key creation.Cache securely. Never log the raw value.
Token usedEvery authenticated request.Send via Authorization: Bearer header. Always over HTTPS.
Token near expiry60 seconds before exp claim.SDK auto-refreshes silently. Manual refresh available.
Token expiredAfter lifetime elapses.Server returns 401 with code token_expired. Refresh and retry once.
Token revokedManually rotated or compromised.Server returns 401 with code token_revoked. Re-authenticate.

Authentication errors

Auth failures always include a stable error.code in the body — branch on the code, not the message.

Statuserror.codeLikely causeHow to fix
401unauthorizedHeader missing, malformed, or token not recognized.Confirm Authorization: Bearer <token> is set and the key has not been revoked.
401token_expiredAccess token is past its exp time.Refresh the token and retry the request once.
401token_revokedKey was rotated or revoked in the dashboard.Re-authenticate with the new credentials.
403forbiddenToken is valid but the scope does not cover this endpoint.Check the requiredScope field in the error body and grant it on the key.
403ip_restrictedRequest came from an IP outside the key’s allowlist.Update the key’s IP allowlist or call from an approved range.
401authentication_timeoutThe session reached the idle timeout for interactive OAuth flows.Restart the OAuth authorization flow to obtain fresh tokens.
429rate_limitedToo many auth attempts in a short window.Honor the Retry-After header. The SDK does this automatically.

Security best practices

The single biggest source of API key incidents is accidental commits. The rules below cost a few minutes each and prevent the painful ones.

RuleWhy it matters
Read keys from environment variablesHard-coding leaks them via repos, screenshots, and stack traces. .env files belong in .gitignore.
Rotate keys every 90 daysPeriodic rotation limits the window an exfiltrated key remains useful. The dashboard supports zero-downtime rotation with a grace period.
Use the smallest possible scopeA leaked articles:read key cannot delete content. Build separate keys for separate jobs.
Pin keys to IP allowlists where possibleRestricts a stolen key to your own infrastructure even if exfiltrated to an attacker’s laptop.
Never log raw tokensLogs end up in many systems. Scrub Authorization headers before they reach log aggregators.
Verify webhook signaturesWebhook payloads are signed with a separate secret. Reject requests whose HMAC does not match.
Set short timeouts on token cachesCaching a token for hours when the API issued it for an hour creates a window of stale auth failures. Cache to expiry, not forever.
Use sandbox keys for CIContinuous integration runs the same code many times — sandbox traffic is free, recoverable, and isolated.

Where to go next

Was this section helpful?

1. Authenticate with an API key

import { TechWriterClient } from ;

"color: ">#8b949e">// Read the key from the environment — never hard-code it.
const tw = new TechWriterClient({
  apiKey: process.env.TECHWRITER_API_KEY
});

const articles = await tw.articles.list();

2. OAuth 2.0 client credentials

import { TokenManager } from ;

const tokens = new TokenManager({
  clientId: process.env.TW_CLIENT_ID,
  clientSecret: process.env.TW_CLIENT_SECRET,
  scope: [, ]
});

"color: ">#8b949e">// TokenManager caches and refreshes the token automatically.
const accessToken = await tokens.getAccessToken();

3. Refresh tokens

"color: ">#8b949e">// The SDK auto-refreshes 60 seconds before expiry.
"color: ">#8b949e">// You can also force a refresh manually:
const fresh = await tokens.refresh();
console.log(, fresh.expiresAt);

Rotation pattern

Generate the new key first, deploy it alongside the old one, then revoke the old key. The dashboard supports a 24-hour grace period where both keys are valid — long enough to roll a fleet without downtime.