I'm experiencing a problem fetching repository data in my web application using personal access tokens generated by GitHub Apps during OAuth login. Specifically, I'm unable to retrieve private repositories where the user is a collaborator (and not the owner).
To provide a brief overview, my web application allows users to log in through GitHub (OAuth), and it should display all repositories to which the user has access. We specifically want to access repositories where the user is either the repository owner or a collaborator. Repositories can have two visibilities: public or private, resulting in four possible combinations:
- Owner + Public
- Owner + Private
- Collaborator + Public
- Collaborator + Private
The core problem is that the token received from GitHub Apps during OAuth login does not seem to grant access to collaborator + private repositories.
From GitHub settings, it is possible to manually create two types of personal access tokens: classic tokens (https://github.com/settings/tokens ) and fine-grained tokens (https://github.com/settings/tokens?type=beta). It seems that GitHub Apps, which we use for OAuth login, utilise fine-grained tokens.
Strangely, by manually generating a classic personal access token with the repo scope, and using that token for authenticating our repo API request (without modifying the GitHub API query), we can successfully fetch all the repository types - also private repositories the user has collaborated to. However, when authenticating with the token generated by GitHub app or a manually created fine-grained token, we are unable to fetch repositories that are collaborator + private.
Even granting the fine-grained token all possible scopes and possible permissions didn't help with accessing collaborator + private repositories. This suggests that it may currently not be possible to assign the necessary permissions to fine-grained tokens for this specific purpose.
If this is indeed the case, are there any workarounds to overcome this limitation? I've considered creating a classic token on behalf of the logged-in user using the fine-grained token as authentication for creating the new token. However, this approach (if it works) introduces complexity and additional security concerns.
I've also tested using both the GitHub REST API and the GraphQL API (used in the code snippet below) with the same results. Additionally, I've tried using an OAuth App instead of a GitHub App, but the issue persisted.
Code snippet: I use Next.js, NextAuth.js, Prisma and Octokit.
import { getServerSession } from 'next-auth';
import { graphql } from '@octokit/graphql';
import { options } from '../auth/[...nextauth]/options';
import prisma from '@/utils/prisma';
import { NextResponse } from 'next/server';
import comparer from '@/utils/comparer';
interface Repository { nameWithOwner: string; }
interface Repositories { nodes: Repository[]; }
interface Viewer { repositories: Repositories; }
interface QueryResult { viewer: Viewer; }
export const GET = async () => {
const session = await getServerSession(options)
if (!session) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 });
}
const loggedInAccount = await prisma.account.findFirst({
where: { userId: session?.user?.userId, provider: "github" },
});
const graphqlWithAuth = graphql.defaults({
headers: {
authorization: `token ${loggedInAccount?.access_token}`,
// authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`, // For testing with manually created tokens
},
});
const query = `
query {
viewer {
repositories(first: 100, affiliations: [OWNER, COLLABORATOR]) {
nodes {
nameWithOwner
}
}
}
}`;
try {
const result = await graphqlWithAuth<QueryResult>(query);
const { viewer } = result;
comparer(viewer.repositories.nodes);
return NextResponse.json({ repos: viewer.repositories.nodes }, { status: 200 });
}
catch (error) {
console.error(error);
return NextResponse.json({ error: 'An error occurred while fetching repositories' }, { status: 500 });
}
};
I'd greatly appreciate any insights, suggestions, or solutions!
TL;DR: Encountering issues with fetching private repositories a user has collaborated to using personal access tokens generated by GitHub Apps during OAuth login. Manually creared classic tokens work, but fine-grained tokens seem unable to access despite full scopes. Seeking insights or workarounds from the community.