Skip to content

feat(auth): support Atlassian scoped API tokens via Cloud ID#29

Merged
pchuri merged 1 commit into
mainfrom
feat/scoped-api-token-support
Apr 26, 2026
Merged

feat(auth): support Atlassian scoped API tokens via Cloud ID#29
pchuri merged 1 commit into
mainfrom
feat/scoped-api-token-support

Conversation

@pchuri
Copy link
Copy Markdown
Owner

@pchuri pchuri commented Apr 26, 2026

📋 Summary

Adds support for Atlassian's scoped API tokens by routing REST and Agile API requests through the Platform API Gateway (https://api.atlassian.com/ex/jira/{cloudId}) when a Cloud ID is configured. Closes #28.

Atlassian recommends scoped tokens over classic (unscoped) ones, but they can only be used through the gateway URL. Without this change, scoped tokens fail authentication regardless of how the CLI is configured.

🎯 Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

🔍 Changes Made

  • Config layer (lib/config.js): added cloudId to the schema, support JIRA_CLOUD_ID env var, surface routing mode in jira config --show
  • Client layer (lib/jira-client.js): when cloudId is set, build REST (/rest/api/{2,3}) and Agile (/rest/agile/1.0) clients off https://api.atlassian.com/ex/jira/{cloudId}; otherwise keep the existing ${server}/... paths (backward compatible with classic tokens, Jira Data Center, and Jira Server)
  • CLI layer (bin/commands/config.js): added --cloud-id <cloudId> flag, included cloudId in connection-test triggers, updated usage messages
  • 401 hint: when a scoped token request fails auth, surface scope/Cloud ID/email troubleshooting hints (mirrors the pattern used in confluence-cli)
  • Docs: new "Scoped API Tokens (Atlassian Cloud)" section with usage and a pointer to _edge/tenant_info for finding the Cloud ID

🧪 Testing

  • All existing tests pass
  • New tests added for new functionality
  • Manual testing: verified jira config --help exposes the new flag
  • Live verification against an Atlassian Cloud site with a scoped token (recommended before landing — I do not have one to test with)

New unit tests cover:

  • Gateway base URL is built correctly for both REST clients (v2/v3) and the Agile client
  • Direct routing is preserved when cloudId is empty/missing (DC compatibility)
  • Auth credentials are preserved through gateway routing
  • Config layer reads cloudId from stored config, returns '' when unset, and prefers JIRA_CLOUD_ID env var over stored config
  • --cloud-id flag wires through to config.set('cloudId', ...)

📊 Test Results

Test Suites: 8 passed, 8 total
Tests:       185 passed, 185 total

npm run lint clean.

🚀 Deployment Notes

  • No special deployment steps required
  • Backward compatible: existing users without cloudId see no behavior change. Cloud ID is opt-in via --cloud-id flag, JIRA_CLOUD_ID env var, or jira config set cloudId <id>.

📝 Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove the feature works
  • New and existing unit tests pass locally

🔗 Related Issues

💬 Additional Notes

A few design choices worth flagging for review:

  1. cloudId over apiPath: confluence-cli takes a more flexible approach by letting users configure domain=api.atlassian.com + apiPath=/ex/confluence/{cloudId}/rest/api. For jira-cli I picked an explicit cloudId field instead because we have two distinct API surfaces (REST and Agile) constructed in code, so a single higher-level abstraction is cleaner. Happy to switch to the apiPath approach if that's preferred for consistency across the two projects.

  2. No auto-discovery: The original issue suggested auto-deriving Cloud ID. I left that out of this PR to keep the surface small — _edge/tenant_info is documented in the README so users can fetch it manually with one curl. Auto-discovery (calling _edge/tenant_info when cloudId is missing) can come as a follow-up.

  3. Live testing pending: Unit tests cover URL construction and config plumbing, but I do not have an Atlassian Cloud site with a scoped token to verify the gateway actually accepts the request end-to-end. Recommend a quick live smoke test before merging.

Atlassian's scoped API tokens require requests to go through the
Platform API Gateway (api.atlassian.com/ex/jira/{cloudId}) instead
of the site URL. This adds optional Cloud ID configuration that,
when set, automatically routes all REST and Agile API calls through
the gateway.

- Accept cloudId via --cloud-id flag, JIRA_CLOUD_ID env var, or
  `jira config set cloudId`
- Route REST (/rest/api/{2,3}) and Agile (/rest/agile/1.0) clients
  through the gateway base when cloudId is present
- Keep existing direct routing when cloudId is empty (backward
  compatible with classic tokens, Jira Data Center, and Jira Server)
- Surface scoped-token-specific hints on 401 responses

Closes #28
@pchuri pchuri self-assigned this Apr 26, 2026
@pchuri pchuri merged commit b2cddf3 into main Apr 26, 2026
5 checks passed
@pchuri pchuri deleted the feat/scoped-api-token-support branch April 26, 2026 10:21
github-actions Bot pushed a commit that referenced this pull request Apr 26, 2026
# [2.5.0](v2.4.2...v2.5.0) (2026-04-26)

### Features

* **auth:** support Atlassian scoped API tokens via Cloud ID ([#29](#29)) ([b2cddf3](b2cddf3)), closes [#28](#28)
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 2.5.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Support Atlassian scoped API tokens via Platform API Gateway

1 participant