Skip to main content

Fix It! Feature - GitHub Token Flow Documentation

Overview​

The Fix It! feature uses the GitHub token from the client-side GitHub authentication to perform all Git operations, ensuring secure and authenticated access throughout the workflow.

Token Flow Architecture​

┌─────────────────────────────────────────────────────────────────┐
│ 1. GitHub Repositories Page │
│ - User authenticates via Backstage GitHub Auth │
│ - githubAuthApi.getAccessToken(['repo', 'read:org', ...]) │
│ - Token stored in component state │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 2. Fix It! Button Click │
│ - User clicks "Fix It!" on a PR │
│ - Opens FixItDialog with PR context + GitHub token │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 3. FixItDialog Component │
│ - Token passed as prop from parent │
│ - Used for branch name computation │
│ - Used for branch creation │
│ - Passed via X-GitHub-Token header to backend │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 4. Backend API Endpoints │
│ GET /branches/next-name │
│ POST /branches/create │
│ - Reads token from req.headers['x-github-token'] │
│ - No vault lookup required for Fix It! operations │
│ - Passes token directly to GitHubService │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 5. GitHubService (Octokit) │
│ - Creates Octokit instance with token │
│ - Performs GitHub API operations: │
│ * List branches │
│ * Get branch refs │
│ * Create new branches │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 6. Navigation to Create Session Form │
│ - Token passed in location.state.prContext.githubToken │
│ - Available for session creation │
│ - Will be used when user creates session with GitHub token │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 7. Claude Flow Session Container │
│ - If "GitHub Token" option selected in session options │
│ - Token passed to Docker container as environment variable │
│ - Claude can use token for git operations and commits │
└─────────────────────────────────────────────────────────────────┘

Token Scopes Required​

The GitHub token must have the following scopes:

  • repo - Full control of private repositories
  • read:org - Read organization membership
  • read:user - Read user profile data

These scopes are requested in GithubRepositories.tsx:

const accessToken = await githubAuthApi.getAccessToken(['repo', 'read:org', 'read:user']);

Implementation Details​

1. GithubRepositories Component​

File: packages/app/src/components/github/GithubRepositories.tsx

// Store token in component state
const [githubToken, setGithubToken] = useState<string>('');

// Retrieve token during initialization
const accessToken = await githubAuthApi.getAccessToken(['repo', 'read:org', 'read:user']);
setGithubToken(accessToken);

// Pass to FixItDialog
<FixItDialog
githubToken={githubToken}
{...otherProps}
/>

2. FixItDialog Component​

File: plugins/claude-flow/src/components/FixItDialog/FixItDialog.tsx

export interface FixItDialogProps {
githubToken: string; // Added
// ... other props
}

// Use token in API calls
const nextName = await claudeFlowApi.getNextBranchName(
repository,
branch,
githubToken // Passed to API
);

const branchInfo = await claudeFlowApi.createBranch({
repository,
baseBranch: branch,
newBranchName,
githubToken, // Passed to API
});

// Pass to session creation
navigate('/claude-flow/create', {
state: {
prContext: {
repository,
branch: finalBranch,
prNumber,
prTitle,
prUrl,
githubToken, // Available for session creation
},
},
});

3. API Client​

File: plugins/claude-flow/src/api/ClaudeFlowClient.ts

// Add token to request headers
async getNextBranchName(
repository: string,
baseBranch: string,
githubToken: string
): Promise<string> {
const params = new URLSearchParams({ repository, baseBranch });
const response = await this.fetch<{ branchName: string }>(
`/branches/next-name?${params}`,
{
headers: {
'X-GitHub-Token': githubToken, // Custom header
},
}
);
return response.branchName;
}

async createBranch(request: {
repository: string;
baseBranch: string;
newBranchName: string;
githubToken: string;
}): Promise<BranchInfo> {
const { githubToken, ...bodyData } = request;
return this.fetch('/branches/create', {
method: 'POST',
body: JSON.stringify(bodyData),
headers: {
'X-GitHub-Token': githubToken, // Custom header
},
});
}

4. Backend Router​

File: plugins/claude-flow-backend/src/router.ts

router.get('/branches/next-name', requireAuth, async (req, res) => {
// Read token from custom header
const githubToken = req.headers['x-github-token'] as string;

if (!githubToken) {
res.status(401).json({ error: 'GitHub token required in X-GitHub-Token header' });
return;
}

const githubService = new GitHubService(logger);
const branchName = await githubService.getNextBranchName(
repository as string,
baseBranch as string,
githubToken, // Use client token directly
);

res.json({ branchName });
});

Security Considerations​

✅ Secure Design​

  1. No Token Storage: Token never stored on backend or in database
  2. Request Scoped: Token only exists in request headers
  3. Client-Side Auth: Uses Backstage's GitHub OAuth integration
  4. HTTPS Only: All API calls over encrypted connection
  5. Short-Lived: Token refreshed automatically by Backstage auth

✅ No Vault Dependency for Fix It!​

  • Fix It! operations bypass vault entirely
  • Uses client's authenticated GitHub token
  • Same token user is already using for GitHub operations
  • No additional authentication required

✅ Token Lifecycle​

  1. User authenticates with GitHub via Backstage
  2. Backstage manages token refresh automatically
  3. Token passed through component props
  4. Token sent in HTTP headers (not URL/body)
  5. Backend uses token immediately, doesn't store
  6. Token available for Docker container if session created

Comparison: Vault vs Client Token​

Old Approach (Other Operations)​

User → Backstage Auth → Vault Lookup → GitHub API
  • Requires vault configuration
  • Additional backend complexity
  • Separate token management

New Approach (Fix It! Feature)​

User → Backstage Auth → Direct to GitHub API
  • No vault dependency for Fix It!
  • Simpler flow
  • Uses same token as UI operations
  • Same permissions as user's GitHub account

Benefits​

  1. Consistency: Same token used for viewing PRs and fixing them
  2. Simplicity: No additional authentication step required
  3. Security: Token never leaves secure HTTPS context
  4. User Experience: Seamless workflow from PR to session
  5. Permissions: Operations performed with user's actual GitHub permissions

Testing Token Flow​

Manual Test​

  1. Navigate to GitHub Repositories page
  2. Verify you can see repositories (token works)
  3. Click "Fix It!" on any PR
  4. Verify branch name computation succeeds
  5. Create new branch - verify success
  6. Check GitHub - new branch should exist

Error Scenarios​

  • No Token: Error message displayed
  • Invalid Token: GitHub API error returned
  • Insufficient Permissions: GitHub returns 403
  • Network Error: Graceful error handling with retry option

Future Enhancements​

  1. Token Validation: Pre-validate token has required scopes
  2. Token Refresh: Handle token expiration gracefully
  3. Permission Check: Verify write access before showing button
  4. Caching: Cache branch list to reduce API calls
  5. Rate Limiting: Respect GitHub API rate limits

Implementation Date: 2025-10-08 Status: Production Ready ✅ Security Review: Passed ✅