@scoutflo/integration-sdk
v1.0.34
Published
TypeScript SDK for third-party integrations with auth lifecycle management.
Maintainers
Readme
Scoutflo Integration SDK
This project is a TypeScript SDK for managing third-party integrations and their authentication lifecycles, supporting multiple providers and authentication strategies.
Project Structure
src/index.ts: SDK entry point, exposes thecreateSDKfunction.src/connection-manager.ts: Core logic for managing and resolving connections.src/providers/: Provider-specific logic (e.g.,sentry.provider.ts).src/storage/: Storage interface and implementations:mongodb.storage.ts: MongoDB storage providerredis.storage.ts: Redis storage providerstorage.interface.ts: Storage provider interface
src/strategies/: Authentication strategies:api-key.strategy.ts: API Key authbasic.strategy.ts: Basic Authmapped-credentials.strategy.ts: provider-mapped static credential authoauth.strategy.ts: reusable OAuth app lifecycle core for provider adapters
src/providers/atlassian-oauth.adapter.ts: Atlassian adapter over the shared OAuth coresrc/providers/atlassian-oauth.helpers.ts: Atlassian-specific helper functions for state, scope, cache-key, runtime, and sibling-token handlingsrc/types/: Shared types and enumsusage/my-service.ts: Example usage of the SDK in a servicepackage.json: Project metadata, scripts, and dependenciestsconfig.json: TypeScript compiler configuration
Setup and Installation
Clone or create the project directory:
git clone <repo-url> cd scoutflo-integration-sdkInstall dependencies:
npm installThis will install TypeScript, Zod, and the example database drivers (MongoDB, Redis, Mongoose).
Usage
Ensure your MongoDB and/or Redis instances are running if you are using the provided storage implementations.
Build the project:
npm run buildThis will compile the TypeScript files into JavaScript in the
distdirectory.Use the SDK in your service: See
usage/my-service.tsfor an example. A minimal example:import { Model } from "mongoose"; import { createSDK } from "../src"; import { MongoDBStorage } from "../src/storage/mongodb.storage"; import { Integration } from "../src/types"; const model = new Model<Integration>(); const storage = new MongoDBStorage(model); const sdk = createSDK(storage); // Create or resolve connections using sdk.createConnection and sdk.resolveConnection
Atlassian Jira/Confluence lifecycle
The SDK now includes adapter-backed lifecycle support for Atlassian Jira, JSM, and Confluence.
Current architecture:
OAuthStrategyowns shared OAuth mechanics such as install URL shell assembly, code exchange, refresh exchange, cache lookup, lock handling, and token invalidation.AtlassianProviderremains the public Atlassian facade and still owns the resolved runtime contract.AtlassianOAuthAdapterowns Atlassian-specific callback and refresh orchestration.atlassian-oauth.helpers.tsowns smaller Atlassian-specific helpers for scope lookup, state shaping, cache-key compatibility, runtime shaping, and sibling refresh-token synchronization.
What is supported:
- install URL generation for Atlassian OAuth 3LO through the shared OAuth core
- callback handling that returns a single selected-product integration payload
- sibling Atlassian integration scope-union support when extending an existing site install
- install context recovery through encoded OAuth
statefor sibling integration installs - Redis-backed short-lived access-token caching with TTL
- refresh-token based access-token renewal with sibling Atlassian refresh-token synchronization
- normalized Jira/JSM/Confluence resolved runtime output for caller services
Minimal shape:
import Redis from "ioredis";
import { createSDK } from "../src";
import { MongoDBStorage } from "../src/storage/mongodb.storage";
import { RedisStorage } from "../src/storage/redis.storage";
const persistentStorage = new MongoDBStorage(model);
const cacheStorage = new RedisStorage(new Redis(process.env.REDIS_URL));
const sdk = createSDK(persistentStorage, {
cacheStorage,
atlassian: {
clientId: process.env.ATLASSIAN_CLIENT_ID!,
clientSecret: process.env.ATLASSIAN_CLIENT_SECRET!,
redirectUri: process.env.ATLASSIAN_REDIRECT_URI!,
identityResolver: async (userId) => {
return {
account_id: "account-id",
created_by: userId,
};
},
},
});
const install = await sdk.buildInstallUrl({ user_id: "user-123", account_id: "acct-123", provider: "jira" as const });
const callback = await sdk.handleInstallCallback({ code: "oauth-code", state: install.state, provider: "jira" as const });
await sdk.createConnection(callback.integration);
const jiraRuntime = await sdk.resolveConnection("jira-integration-id");Atlassian install behavior in the current V1 flow:
- scope union lookup runs only for Atlassian sibling providers (
jira,confluence,jsm) - sibling scope lookup is account-scoped via
account_id - refresh-token rotation is synchronized across Atlassian sibling integrations for the same Scoutflo
account_id - non-Atlassian integrations do not trigger Atlassian scope lookup
- Redis token cache key format is
integration:{provider}:{integration_id}:app_user:{account_id}:access_token - Redis refresh lock key format is
integration:{provider}:{integration_id}:app_user:{account_id}:refresh_lock resolveConnection()still returns the Atlassian-specific runtime shape fromAtlassianProvider
IMPORTANT V1 NOTE:
- callback now fails fast when Atlassian returns multiple accessible resources.
- SDK throws
atlassian_site_selection_requiredand does not silently chooseaccessible-resources[0]. - product warning: Atlassian multi-site selection UX/API is still pending and must be implemented before broader rollout.
- backlog item (mandatory): add explicit site-selection contract and persistence rules for multi-site callbacks.
OAuth callback-state security deferral (explicit):
- accepted risk: callback
stateis used for context recovery, but it is not yet a signed, replay-protected integrity boundary. - do not treat as secure CSRF-grade state yet.
- why deferred: V1 prioritized lifecycle migration and blast-radius control across SDK, Gateway, and Voyager.
- owner: Platform Integrations (SDK + Gateway joint ownership)
- target version/date: SDK
2.0.0by April 30, 2026 - mandatory V2 work: signed + replay-resistant state integrity, deterministic reject semantics, and negative tests for tampered/replayed/mismatched callback state.
Important notes:
handleInstallCallback(...)returns the selected Atlassian integration payload but does not persist it automatically.cacheStorageis required when Atlassian lifecycle support is enabled.- access tokens are cached in Redis per integration, while refresh tokens remain in persistent integration storage.
- when a site already has sibling Atlassian integrations, the SDK can extend requested scopes and synchronize rotated refresh tokens across those sibling Atlassian integrations.
Versioning Rule (Documented Policy)
Current decision:
- keep current semver line for this controlled rollout (no immediate major bump required right now).
Before wider/shared adoption:
- either bump major to
2.0.0, or - make the interface fully backward-compatible and document that compatibility explicitly.
Do not widen adoption without one of the two conditions above being completed.
Rollout Checks Before Preprod/Prod
Run and capture evidence for all three paths before promoting:
- Slack install/callback path:
npm run test:slack-lifecycle
- Slack token refresh path:
npm run trace:slack-requested-flow
- Atlassian install/callback happy path (current assumptions):
npm run test:atlassian-lifecycle
Customization
- Storage: Implement the
IStorageProviderinterface insrc/storage/storage.interface.tsto connect to your actual data store (e.g., a specific MongoDB database, a different Redis configuration, or another technology). - Providers: Add new provider logic in
src/providers/and update theConnectionManagerto support them. - Authentication Strategies: Add or modify strategies in
src/strategies/for different authentication methods. - Types: Extend or modify types in
src/types/as needed for your integrations.
Scripts
npm run build: Compile TypeScript to JavaScript indist/npm publish: Publish the package (private)
Dependencies
typescript,zod,ioredis,mongodb,mongoose,redis
For more details, see the code in the respective directories and the example in usage/my-service.ts.
