Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions apps/api/src/services/github-token-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ const TOKEN_REFRESH_BUFFER_MS = 10 * 60 * 1000;
export type GitHubTokenContext =
| { taskId: string }
| { userId: string; workspaceId?: string | null }
| { server: true };
| { server: true; workspaceId?: string | null };

export async function getGitHubToken(context: GitHubTokenContext): Promise<string> {
if ("server" in context) return getServerToken();
if ("server" in context) return getServerToken(context.workspaceId);
if ("taskId" in context) return getTokenForTask(context.taskId);
return getTokenForUser(context.userId, context.workspaceId);
}

async function getServerToken(): Promise<string> {
async function getServerToken(workspaceId?: string | null): Promise<string> {
if (isGitHubAppConfigured()) {
try {
return await getInstallationToken();
} catch (err) {
logger.warn({ err }, "Installation token failed, falling back to PAT");
return getPatFallback();
return getPatFallback(workspaceId);
}
}
return getPatFallback();
return getPatFallback(workspaceId);
}

async function getTokenForTask(taskId: string): Promise<string> {
Expand All @@ -44,7 +44,7 @@ async function getTokenForTask(taskId: string): Promise<string> {

if (!task?.createdBy) {
// No user associated — use server/installation token (e.g., system-created tasks)
return getServerToken();
return getServerToken(task?.workspaceId);
}
return getTokenForUser(task.createdBy, task.workspaceId);
}
Expand All @@ -60,8 +60,8 @@ async function getTokenForUser(userId: string, workspaceId?: string | null): Pro
}
return refreshUserToken(userId, workspaceId);
} catch (err) {
logger.warn({ userId, err }, "No stored user token, falling back to PAT");
return getPatFallback(workspaceId);
logger.warn({ userId, err }, "No stored user token, falling back to server token");
return getServerToken(workspaceId);
}
}

Expand All @@ -84,7 +84,7 @@ async function doRefreshUserToken(userId: string, workspaceId?: string | null):

if (!clientId || !clientSecret) {
await deleteUserGitHubTokens(userId);
return getPatFallback(workspaceId);
return getServerToken(workspaceId);
}

try {
Expand Down Expand Up @@ -128,8 +128,8 @@ async function doRefreshUserToken(userId: string, workspaceId?: string | null):
} catch (err) {
// Don't delete tokens on transient errors (network, 5xx) — only the
// definitive revocation cases above delete them before re-throwing.
logger.warn({ userId, err }, "Token refresh failed, falling back to PAT");
return getPatFallback(workspaceId);
logger.warn({ userId, err }, "Token refresh failed, falling back to server token");
return getServerToken(workspaceId);
}
}

Expand Down
Loading