@oneb/sdk
v0.6.0
Published
Official Node.js SDK for OneB — OAuth2 + Workspace/Account API for third-party apps
Maintainers
Readme
@oneb/sdk
Official Node.js SDK for OneB — OAuth2 Authorization Code flow + Workspace/Account API for third-party apps.
Install
npm install @oneb/sdk
# or: pnpm add @oneb/sdk / yarn add @oneb/sdkRequires Node.js 18.17+ (native fetch). ESM only. Runtime dependency on jose for RS256 JWT verification.
Quick start
import { OneB } from '@oneb/sdk';
const oneb = new OneB({
clientId: process.env.ONEB_CLIENT_ID!,
clientSecret: process.env.ONEB_CLIENT_SECRET!,
publicKey: process.env.ONEB_PUBLIC_KEY_B64, // base64-encoded SPKI PEM
redirectUri: 'https://myapp.example/oauth2/result',
scopes: ['invoice.read'],
env: 'prod', // or 'dev' for 1-b.dev sandbox
});
// 1. Build authorize URL and redirect the user
const { url, state } = oneb.buildAuthorizationUrl({ tenant: 'acme' });
saveStateInSession(state);
res.redirect(url);
// 2. In /oauth2/result handler — exchange code for tokens
const { access_token, refresh_token } = await oneb.exchangeCode(req.query.code);
oneb.setToken(access_token, refresh_token);
// 3. Call APIs (Bearer-authenticated)
const me = await oneb.workspace.getUserDetails();
const acc = await oneb.account.getUserDetails();
const auth = await oneb.workspace.getAuthDetails();
// 4. Verify the JWT locally (optional but recommended)
const payload = await oneb.verifyToken();
console.log(payload.tenantAlias, payload.scopes);
// 5. Refresh / revoke
await oneb.refreshToken();
await oneb.revokeToken();A full Express demo lives in sdk-node-demo — clone it, point at your app, run yarn start.
Configuration
new OneB({
clientId: string, // required
clientSecret: string, // required
publicKey?: string, // base64 SPKI PEM, required for verifyToken()
redirectUri?: string, // required to build authorize URLs
scopes?: string[], // default scopes for buildAuthorizationUrl
env?: 'prod' | 'dev', // default 'prod'
urls?: { // per-endpoint overrides (win over env)
authorize?: string,
api?: string,
},
http?: {
connectTimeoutMs?: number, // default 6000
timeoutMs?: number, // default 24000
retries?: number, // default 3 (GET only)
userAgent?: string,
fetch?: typeof fetch,
},
signal?: AbortSignal,
});Default endpoints
| Env | Authorize | API base |
|---|---|---|
| prod | https://account.oneb.app/oauth/authorize | https://account.oneb.app/s/ |
| dev | https://accounts.1-b.dev/oauth/authorize | https://accounts.1-b.dev/s/ |
OAuth2 flow
┌────────────────────────┐
│ Your Node.js server │
└───────────┬────────────┘
│ buildAuthorizationUrl()
▼
┌──── 302 ──────────────── ┐
User browser ──▶│ account.oneb.app/oauth/ │── login & consent
└──────────────────────── ┘
│
▼ ?code=...&state=...
┌────────────────────────┐
│ /oauth2/result │── exchangeCode()
└───────────┬────────────┘
│ access_token + refresh_token
▼
┌────────────────────────┐
│ setToken() │── workspace.* / account.*
└────────────────────────┘State (CSRF) is generated automatically (32-hex random) unless you pass state explicitly. Validate it in your callback before calling exchangeCode.
API surface
oneb.buildAuthorizationUrl({ tenant?, scopes?, state?, bot? })oneb.exchangeCode(code)→{ access_token, refresh_token, expires_in, ... }oneb.refreshToken(refresh?)→ new token (uses stored refresh if omitted)oneb.revokeToken(token?)→void(clears stored iftokenomitted)oneb.setToken(access, refresh?)/getToken()/clearToken()/hasToken()oneb.decodeToken()— unsafe, no signature check (debug only)oneb.verifyToken()— RS256 verify, returnsTokenPayloadoneb.workspace.*—getUserDetails,getAuthDetails,getUserBrowser,getAppDetails,getTariffDetails,getNewsFeed,getNewsBadge,createInvitation,listUsers,changeRole,rememberActiononeb.account.*—getUserDetailsoneb.createAccountUrl(path?)— deep link to Account UIoneb.createOpenUrl(tenant?)— deep link to open app
Errors
All errors inherit from OnebError:
| Class | When |
|------------------------|---------------------------------------|
| OnebClientError | HTTP 4xx (except 429) |
| OnebRateLimitError | HTTP 429 — retryAfterMs populated |
| OnebServerError | HTTP 5xx |
| OnebNetworkError | DNS/connection failure |
| OnebTimeoutError | Request exceeded timeoutMs |
| OnebValidationError | Bad OneBOptions, invalid JWT, etc. |
import { OnebClientError } from '@oneb/sdk';
try {
await oneb.exchangeCode(code);
} catch (e) {
if (e instanceof OnebClientError && e.status === 400) {
// e.message comes from `error_description` in the token response
}
}License
MIT
