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 ✅