AI Agents SDE Task Viewer
      • Context
      • Plan
      • Prd
  1. Home
  2. AgentSDE
  3. agent-core
  4. gh-541
  5. plan
  6. plan.md
plan.md(3.3 KB)· Apr 23, 2026· 2 min read
  • Summary
  • Files
  • Steps
  • Verification
  • Risks
  • Assumptions

Plan — BJ-1: AtlassianOAuthAuthProvider abstract base#

Summary#

Add an abstract NestJS provider that models the PlatformAuthProvider interface using the OAuth 2.0 refresh-token flow (rotating refresh tokens). It is the shared auth foundation both Bitbucket and Jira providers (BJ-2, BJ-3) will extend.

Files#

PathActionPurpose
src/atlassian/atlassian-oauth-auth.provider.tscreateAbstract class implementing PlatformAuthProvider with refresh-token flow + concurrency guard.
src/atlassian/atlassian-oauth-state.repo.tscreateMinimal typed interface + injection token for the state repo (actual impl lands in BJ-5).
src/atlassian/index.tscreateBarrel exporting the abstract class, state repo interface, and token.
src/atlassian/atlassian-oauth-auth.provider.spec.tscreateUnit tests via a concrete test subclass; injected HTTP client + repo mock.

Steps#

  1. Define AtlassianOAuthStateRepo interface (loadRefreshToken(platform: string): Promise<string | null>, saveRefreshToken(platform: string, token: string): Promise<void>) plus ATLASSIAN_OAUTH_STATE_REPO injection token in atlassian-oauth-state.repo.ts.
  2. Implement abstract AtlassianOAuthAuthProvider in atlassian-oauth-auth.provider.ts: constructor takes subclass config { tokenEndpoint, clientId, clientSecret, refreshTokenBootstrap, platform }, injected AtlassianOAuthStateRepo, and optional fetchFn (defaults to global fetch) for testability.
  3. Implement getToken() — return cached access token when > 5 min from expiry; otherwise run refresh through a single in-flight refreshPromise (copy the guard pattern from src/github/github-app-auth.provider.ts:60-70). Do not overwrite cache on error.
  4. Implement refreshAccessToken() — POST <tokenEndpoint> form-encoded grant_type=refresh_token&refresh_token=<current>&client_id=<id>&client_secret=<secret>; on success persist the rotated refresh_token via stateRepo.saveRefreshToken(platform, ...) before returning access token.
  5. Add abstract getBotUsername(): string and JSDoc describing the refresh-token rotation invariant (Atlassian rotates on each refresh; persistence must happen before returning).
  6. Create src/atlassian/index.ts barrel re-exporting the abstract class, interface, and token.
  7. Add atlassian-oauth-auth.provider.spec.ts with a minimal concrete subclass exercising: cached token reuse, preemptive refresh within 5-min buffer, concurrent getToken() calls share one refresh, refresh persists rotated token, endpoint failure propagates without corrupting state.

Verification#

  • npm run build passes (tsc strict, abstract class conforms to PlatformAuthProvider).
  • npm run test -- atlassian-oauth-auth passes all new spec cases (happy, concurrency, rotation persistence, error).
  • npm run lint zero warnings.

Risks#

  • AtlassianOAuthStateRepo here is an interface only; BJ-5 supplies the impl. Consumers (BJ-2/BJ-3) must not instantiate the abstract class until a real repo provider is registered.

Assumptions#

  • Target base branch is rc/atlassian-integration (per issue), which already contains BJ-0 (PlatformAuthProvider interface + GitHub auth providers from #540).
  • Atlassian token endpoint accepts standard application/x-www-form-urlencoded OAuth 2.0 refresh-token grant and returns { access_token, expires_in, refresh_token }.
ContextPrd