CustomGPTs Action to Read Private GitHub Repository Content Using Fine-Grained Bearer Token

Hi everyone,

I’m currently working on a project where I need my custom GPTs to access a private GitHub repository using fine-grained personal access tokens. Here’s a quick overview of what I’m trying to achieve and the issues I’m facing:

Objective:

  • Access the private repository MY_USERNAME/MY_REPO_NAME on GitHub.
  • Use fine-grained personal access tokens for authentication.
  • Ensure the custom GPTs can fetch and navigate through the repository contents.

Steps Taken:

  1. Created an OpenAPI Specification:

    • Defined the getRepositoryContents operation to fetch the contents of the repository or specific subfolders.
    • Included the necessary parameters (owner, repo, and path) and security schemes.
    • I’ve also ensured that my fine-grained personal GitHub access token is correctly entered in the GUI under the Bearer section.

Issue:
The custom GPTs is connecting to the wrong repository. For example: instead of connecting to /repos/my_username/my_repo/contents it’s connecting to /repos/facebook/react/contents

Action Call

{
“domain”: “api. github .com”,
“method”: “get”,
“path”: “/repos/{owner}/{repo}/contents”,
“operation”: “getRepositoryContents”,
“operation_hash”: “xxx”,
“is_consequential”: false,
“params”: {
“owner”: “facebook”,
“repo”: “react”
}
}

Here's my current OpenAPI 3 script:
openapi: 3.0.0
info:
  title: GitHub Repository Management API
  description: API for managing private GitHub repositories with explicit credentials.
  version: 1.0.0
servers:
  - url: https://api.github.com
    description: GitHub API server
paths:
  /repos/{owner}/{repo}/contents:
    get:
      operationId: getRepositoryContents
      summary: Get contents of a repository or a specific subfolder
      parameters:
        - name: owner
          in: path
          required: true
          schema:
            type: string
          example: MY_USERNAME
        - name: repo
          in: path
          required: true
          schema:
            type: string
          example: MY_REPO_NAME
        - name: path
          in: query
          required: false
          schema:
            type: string
          example: ''
          description: Path to the folder or file within the repository. Leave empty for the root.
      responses:
        '200':
          description: Contents of the repository or subfolder
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    name:
                      type: string
                    path:
                      type: string
                    sha:
                      type: string
                    size:
                      type: integer
                    url:
                      type: string
                    html_url:
                      type: string
                    git_url:
                      type: string
                    download_url:
                      type: string
                    type:
                      type: string
                    _links:
                      type: object
                      properties:
                        self:
                          type: string
                        git:
                          type: string
                        html:
                          type: string
      security:
        - defaultToken: []
components:
  schemas:
    Repository:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        full_name:
          type: string
        owner:
          $ref: '#/components/schemas/User'
        private:
          type: boolean
        html_url:
          type: string
        description:
          type: string
        fork:
          type: boolean
        url:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        pushed_at:
          type: string
          format: date-time
        homepage:
          type: string
        size:
          type: integer
        stargazers_count:
          type: integer
        watchers_count:
          type: integer
        language:
          type: string
        forks_count:
          type: integer
        open_issues_count:
          type: integer
        default_branch:
          type: string
    User:
      type: object
      properties:
        login:
          type: string
        id:
          type: integer
        avatar_url:
          type: string
        html_url:
          type: string
securitySchemes:
  defaultToken:
    type: apiKey
    in: header
    name: Authorization
    description: "Predefined GitHub Token"
    example: "Bearer github_pat_XXXXXXX"
security:
  - defaultToken: []
4 Likes

Hello Jessy,

it’s been a while since you wrote this post and I am very curious, how it’s going?

Since I am also experimenting with custom GPTs and actions, I want to share my “experience” with faulty pathes. Just avoid them by all means :sweat_smile: Better specify the pathes one after the other (so instead of e.g.

  • “/repos/{owner}/{repo}/contents”

better do

  • “/repos/my_username/my_repo/contents” and
  • “/repos/facebook/react/contents”

or whatever…). This way your GPT never has to “guess” the path it’s connecting to.

But please help me Jessy :tired_face: How did you get the fine-grained bearer token from github to work in the GPT action??

The classic token works like a charm for me. But I want the security advantages of the fine-grained tokens. So I created a new fine-grained token with the following properties:

  1. Token name: testest
  2. Resource owner: myself
  3. Expiration: 30 days
  4. Description: empty
  5. Repository access: Only select repositories (my-gpt-repo)
  6. Repository permissions: Contents, Metadata
  7. Account permissions: empty

Afterwards I put it into the Authentication type just as I did with the classic token:

  • API key: paste github token
  • Auth type: Bearer

And I get a 404 not found error for the requested data. :question:
I already tried setting all permissions to read in the token - no change. :woman_shrugging:
I tested the token with curl - works! :+1:
I also tried a non-existing token in my GPT: this leads to a “wrong credentials” error. :+1:
Only when I use an existing, non-expired, supi-dupi fine-grained token, I get a 404 not found. :question:

How did you do this? Did anybody here get the fine-grained token to work?

Any help appreciated :pray: Thanks in advance!