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 repositoriesread:org- Read organization membershipread: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
- No Token Storage: Token never stored on backend or in database
- Request Scoped: Token only exists in request headers
- Client-Side Auth: Uses Backstage's GitHub OAuth integration
- HTTPS Only: All API calls over encrypted connection
- 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
- User authenticates with GitHub via Backstage
- Backstage manages token refresh automatically
- Token passed through component props
- Token sent in HTTP headers (not URL/body)
- Backend uses token immediately, doesn't store
- 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
- Consistency: Same token used for viewing PRs and fixing them
- Simplicity: No additional authentication step required
- Security: Token never leaves secure HTTPS context
- User Experience: Seamless workflow from PR to session
- Permissions: Operations performed with user's actual GitHub permissions
Testing Token Flow
Manual Test
- Navigate to GitHub Repositories page
- Verify you can see repositories (token works)
- Click "Fix It!" on any PR
- Verify branch name computation succeeds
- Create new branch - verify success
- 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
- Token Validation: Pre-validate token has required scopes
- Token Refresh: Handle token expiration gracefully
- Permission Check: Verify write access before showing button
- Caching: Cache branch list to reduce API calls
- Rate Limiting: Respect GitHub API rate limits
Implementation Date: 2025-10-08 Status: Production Ready ✅ Security Review: Passed ✅