API Documentation Portal
Central hub where teams browse OpenAPI contracts, explore endpoints, and access integration and testing guides.
YAML specs
This portal
Validation
API Gateway v2
Handshake, encrypted proxy, and route allowlist.
Dynamic Key v2Key Management v2
QR generation, reverse QR state, PIN consume, and login resolution.
QR APIWeb SDK
TypeScript client for Dynamic Key V2 handshake and encrypted proxy.
v0.1.3Authentication
Login, users, roles, and session management.
Coming soonQR Flows
End-to-end QR login and device linking workflows.
Coming sooncontracts/ are served independently from application runtimes. Use the API selector above to switch between specifications.
Dynamic Key V2
End-to-end encryption protocol that replaces the shared-secret handshake (v1). Uses ECDH P-256, HKDF-SHA256, and AES-256-GCM.
POST /api/info. Requests without
X-Dynamic-Key-Version: 2 do not enter the v2 flow.Integration flow
Required headers
| Header | Handshake | Encrypted request |
|---|---|---|
X-Dynamic-Key-Version: 2 | β | β |
X-Session-Id | β | β |
Authorization: Bearer | β | β |
Content-Type: application/json | β | β |
Handshake β POST /api/info/v2
{
"clientPublicKey": "BASE64_SPKI_EPHEMERAL_KEY",
"device": {
"id": "browser-uuid-v4",
"platform": "browser"
},
"client": {
"type": "internal",
"clientId": "internal-web-client"
}
}
Response
{
"serverPublicKey": "...",
"sessionId": "opaque-session-id",
"token": "jwt",
"expireToken": 0,
"expiresAt": "2026-06-04T00:00:00.000Z"
}
Encrypted request β POST /api/request/v2
Internal plaintext describes the upstream route:
{
"method": "GET",
"path": "/countries/get",
"headers": {},
"query": {},
"body": null
}
Sent encrypted as an envelope:
{
"nonce": "base64-12-unique-bytes",
"data": "base64(ciphertext || authTag)"
}
Route allowlist
Only routes explicitly allowed in the gateway can be proxied via v2:
POST /users/loginGET /users/getbyid/:idGET /qr/get/reverse/:BFPGET /companies/getbyid/:idCompanyGET /countries/get,/lang/get, etc.
contracts/api-gateway-v2.yaml β
QA: qa/dynamic-key-v2.md β Web SDK: @nimbus/sdk-webWeb SDK β @nimbus/sdk-web
TypeScript reference client for Dynamic Key V2 in browsers. Handles handshake, session derivation, encryption, and protected requests against API Gateway v2.
v0.1.3 β published to AWS CodeArtifact as @nimbus/sdk-web
sdk/nimbus-sdk-web-v2. Remains independent from application UI β consume via a thin adapter behind VITE_API_SECURITY_MODE=v2.
Responsibilities
- Dynamic Key V2 handshake (
POST /api/info/v2) - ECDH P-256 + HKDF-SHA256 session key derivation
- AES-256-GCM encrypt/decrypt for proxy envelopes
- Protected request client (
POST /api/request/v2) - Optional session storage adapter (NIM-944)
Install from CodeArtifact
aws codeartifact login \ --tool npm \ --repository nimbus-sdk-web-v2 \ --domain nimbus \ --domain-owner $AWS_ACCOUNT_ID npm install @nimbus/sdk-web
Install from monorepo
cd sdk/nimbus-sdk-web-v2 npm install npm run build
Configuration
| Field | Description |
|---|---|
gatewayBaseUrl | Gateway origin for the selected environment |
client.type | internal or external |
client.clientId | Allowlisted client ID on the gateway |
device.id | Browser or device instance ID |
device.platform | e.g. browser |
fetcher | Optional custom fetch for tests or Node scripts |
sessionStorage | Optional DynamicKeySessionStorage adapter |
Trailing slashes on gatewayBaseUrl are stripped automatically.
Session lifecycle
- Reuse in-memory session when not expired.
- Try
sessionStorage.load()when an adapter is configured. - Perform a fresh handshake via
POST /api/info/v2. - Persist session through
sessionStorage.save()after handshake (when adapter supports it).
Basic usage
import { SecureApiClient } from '@nimbus/sdk-web';
const client = new SecureApiClient({
gatewayBaseUrl: 'https://apiauthdev.nimbus-id.com',
client: { type: 'internal', clientId: 'internal-web-client' },
device: { id: 'browser-or-device-id', platform: 'browser' },
});
await client.ensureSession();
const data = await client.protectedRequest({
request: {
method: 'GET',
path: '/qr/get/reverse/example-bfp',
query: {},
body: {},
headers: {},
},
});
Public API
SecureApiClientβ recommended entry pointDynamicKeyClientβ handshake onlyencryptJson/decryptJsonβ low-level cryptoNimbusSdkError+SDK_ERRORβ typed errorsEncryptedSessionStorageβ storage scaffold (NIM-944, persistence pending)createDynamicKeyV2Aadβ AAD helper forv2:{sessionId}
EncryptedSessionStorage load()/save() throw NIMBUS_SDK_STORAGE_UNAVAILABLE until NSSS root-key encryption ships. The SDK re-handshakes when restore is unavailable.Compatible frontend stacks
The SDK is framework-agnostic. It only requires a browser runtime with Web Crypto API and fetch.
| Stack | Integration pattern |
|---|---|
| Angular | Injectable service wrapping SecureApiClient |
| Ionic | Same Angular service pattern (Capacitor / Cordova WebView) |
| React / Next.js | Singleton client + custom hook or context provider |
| Vue / Nuxt | Composable (useSecureApiClient) or plugin |
| Svelte / SvelteKit | Module store or onMount session bootstrap |
| Vanilla TS / JS | Direct SecureApiClient usage in app bootstrap |
Not supported: server-side rendering without a browser crypto.subtle context. Run the SDK in the client bundle only.
Frontend integration
- Install
@nimbus/sdk-webfrom CodeArtifact or build from the monorepo. - Wrap
SecureApiClientin a framework-specific adapter (service, hook, composable). - Gate legacy V1 vs V2 with an environment flag (e.g.
VITE_API_SECURITY_MODE). - Call
ensureSession()on app start or before protected calls. - Route business API calls through
protectedRequest()β never call microservice URLs directly.
Examples
Angular service
import { SecureApiClient } from '@nimbus/sdk-web';
@Injectable({ providedIn: 'root' })
export class ApiClientV2Service {
private client = new SecureApiClient({
gatewayBaseUrl: environment.gatewayUrl,
client: { type: 'internal', clientId: environment.clientId },
device: { id: this.deviceId, platform: 'browser' },
});
async getQrReverse(bfp: string) {
await this.client.ensureSession();
return this.client.protectedRequest({
request: {
method: 'GET',
path: `/qr/get/reverse/${bfp}`,
query: {},
body: {},
headers: {},
},
});
}
}
React hook
import { useCallback, useMemo } from 'react';
import { SecureApiClient } from '@nimbus/sdk-web';
function createClient() {
return new SecureApiClient({
gatewayBaseUrl: import.meta.env.VITE_GATEWAY_URL,
client: { type: 'internal', clientId: import.meta.env.VITE_CLIENT_ID },
device: { id: getDeviceId(), platform: 'browser' },
});
}
export function useSecureApi() {
const client = useMemo(() => createClient(), []);
const getQrReverse = useCallback(async (bfp: string) => {
await client.ensureSession();
return client.protectedRequest({
request: {
method: 'GET',
path: `/qr/get/reverse/${bfp}`,
query: {},
body: {},
headers: {},
},
});
}, [client]);
return { getQrReverse };
}
Security considerations
- Do not persist ephemeral ECDH private keys across page reloads.
- Rotate the session on logout or when
expiresAtis reached. - Use a unique nonce per request β the SDK handles this per call.
- Do not log tokens, session keys, or envelopes in production.
Local smoke test
Start API Gateway V2 locally, then run:
cd sdk/nimbus-sdk-web-v2 GATEWAY_URL=https://localhost:3072 npm run smoke:local
Related documentation
qa/sdk-web-v2.mdβ integration referenceqa/dynamic-key-v2.mdβ protocol QA casescontracts/api-gateway-v2.yamlβ wire contract
Mobile Guide (iOS / Android)
Native app flow with QR, device binding, and Dynamic Key v2.
Device identification
{
"device": {
"id": "installation-uuid",
"platform": "ios" | "android"
}
}
Typical flow
- v2 handshake when the app opens (or when refreshing the token).
- Login via encrypted
/users/loginon the allowlist. - QR:
GET /qr/get/reverse/:BFPto link the device. - Include the
deviceheader on legacy routes that require it.
Suggested libraries
- iOS: CryptoKit (P-256), Security framework.
- Android:
KeyPairGeneratorEC +CipherAES-GCM.
Offline / reconnection
If expiresAt has expired, repeat the handshake before any encrypted request.
Do not cache encrypted responses without validating integrity (GCM auth tag).
Backend Guide
Server-to-server integration and external SDK for partners.
External client (SDK)
{
"client": {
"type": "external",
"clientId": "partner-acme-corp"
},
"device": {
"id": "server-instance-id",
"platform": "server"
}
}
Allowlist and restrictions
external clients only access explicitly enabled routes.
Any other route returns DYNAMIC_KEY_V2_ROUTE_NOT_ALLOWED.
Downstream microservices
The gateway decrypts, validates the allowlist, and forwards to internal services (Auth, QR, etc.). Microservices do not implement Dynamic Key β they receive normal HTTP requests from the gateway.
Required configuration
JWT_SECRETfrom Store Keys (/getKeys).- Service URL variables (
AUTH_SERVICES_URL, etc.). - Logs with
safeErrorLogβ do not expose secrets.
QA Guide
Practical layer to validate that OpenAPI contracts work at runtime.
Full reference in qa/.
What to test on /api/info/v2
| Case | Expected |
|---|---|
| Valid handshake with correct SPKI | 200 + sessionId + token |
| Missing X-Dynamic-Key-Version header | 400 DYNAMIC_KEY_V2_MISSING_VERSION |
| Invalid clientPublicKey | 400 DYNAMIC_KEY_V2_INVALID_PUBLIC_KEY |
What to test on /api/request/v2
| Case | Expected |
|---|---|
| Encrypted GET /countries/get | 200 + encrypted envelope |
| Encrypted POST /users/login | 200 or 401 depending on credentials |
| Route outside allowlist | 404 DYNAMIC_KEY_V2_ROUTE_NOT_ALLOWED |
| Repeated nonce | 400 encryption error |
| Invalid / expired token | 401 or 400 |
| Invalid session | 400 |
Release checklist
- β Spec published and versioned in contracts/
- β Smoke test per category (Auth, QR, Companies, Catalogs)
- β Negative cases: nonce, token, route, session
- β Sanitized examples (no real passwords)
- β Portal points to the correct environment
Reference files
qa/dynamic-key-v2.mdβ handshake and proxyqa/sdk-web-v2.mdβ Web SDK integrationqa/critical-routes.mdβ P0/P1 routesqa/error-cases.mdβ error catalog
Authentication
Documentation for login, user management, roles, and session APIs will be published here as microservice contracts are onboarded to the portal.
Key Management
Extended guides for key lifecycle, secrets store integration, and cryptographic key operations will be added here.
QR Flows
End-to-end QR login, reverse QR, device linking, and mobile-to-web handoff workflows will be documented here with sequence diagrams and integration checklists.
DOCS / CONTRACTS / QA Architecture
How the three Nimbus documentation layers relate.
CONTRACTS β OpenAPI Specs
YAML files that define the real technical contract. Swagger reads them to render endpoints, schemas, and examples.
contracts/ βββ api-gateway-v2.yaml β microservice-apigateway-v2 βββ key-management-v2.yaml β microservice-key-management-v2 βββ upcoming/ β future service specs sdk/nimbus-sdk-web-v2 β @nimbus/sdk-web (client library)
DOCS β Developer Portal
This centralized portal. API spec selector, environment selector, Swagger UI, guides, and Dynamic Key v2 documentation β decoupled from application runtimes.
docs-api-dev.nimbus-id.com β development docs-api-stg.nimbus-id.com β staging docs-api.nimbus-id.com β production
QA β QA Reference
Practical guides: critical routes, headers, positive/negative cases, checklists.
Linked from specs via x-qa-ref.
DevSecOps pipeline (target)
Summary
- DOCS = where you view it
- CONTRACTS = what defines the API
- QA = how you test it