Connect GitHub
Connect GitHub to Minion with your own OAuth App or a fine-grained token, then call the GitHub API from execute and packages.
Connecting GitHub lets your agents and packages call the GitHub REST API as you, without the token ever reaching their code.
Minion has a built-in GitHub preset. You create a GitHub OAuth App, paste its client ID and secret into Minion, and approve the connection once. Minion stores the token encrypted and attaches it to requests for api.github.com and uploads.github.com.
If you only need one automation to read a few repositories, a fine-grained personal access token saved as a secret is simpler. See "Use a personal access token instead" below.
Before you start
- You need to be an owner or admin of your Minion organization. Members can use an integration but can't add an app or connect one.
- You need a GitHub account. A personal account is enough.
- If you want repositories in a GitHub organization that restricts OAuth App access, an owner of that GitHub organization has to approve your OAuth App before it can see org data.
- GitHub allows 5,000 API requests per hour per authenticated user.
Create the OAuth app on GitHub
- Open github.com/settings/applications/new . You can also get there from Settings > Developer settings > OAuth Apps > New OAuth App.
- Enter an Application name and a Homepage URL. Both are shown to you on the consent screen.
- Set Authorization callback URL to exactly:
https://app.minion.codes/oauth/callback - Click Register application.
- Copy the Client ID.
- Click Generate a new client secret and copy the secret. GitHub shows it once.
GitHub OAuth App tokens don't expire on a schedule and come without a refresh token. GitHub does revoke a token that goes unused for a year.
Add it in Minion
- Open app.minion.codes/app/integrations .
- In the OAuth apps card, set Provider to GitHub.
- Leave App name (optional) empty. It defaults to
github. - Paste the Client ID and Client secret.
- Set Default scopes (optional) to the scopes you want, separated by spaces or commas. If you leave it empty, Minion requests
read:useronly. For example:read:user repo. - Leave API hosts empty. The preset fills in
api.github.comanduploads.github.com. - Click Save app.
Pick scopes with care. GitHub OAuth scopes are coarse:
- Read-mostly:
read:user,user:email,notifications,read:org, andpublic_repo(public repositories only, but it includes write access to them). - Private repositories:
repo. There is no read-only scope for private repositories, sorepoalso grants write access. - Gists:
gist.
Connect
- In the Integrations card on the same page, choose your app under OAuth app.
- Leave Name (optional) empty to call the integration
github, or type another lowercase name such asgithub-work. - Leave Extra scopes (optional) empty to use the app's default scopes. On a first connect, anything you type here replaces the defaults, so list every scope you need.
- Click Connect and approve the request on GitHub.
GitHub sends you back to the Integrations page with Connected "github". The row shows status connected and your GitHub login.
An agent can start the same flow with minion.integrations.connect({ provider: 'github' }). It returns a connectUrl. An owner or admin has to open that link while signed in to Minion. The agent can't approve it.
Check it works
Run this with execute. It only reads your profile.
export default async function main() {
const res = await minion.integrations.fetch({
name: 'github',
url: 'https://api.github.com/user',
init: {
headers: {
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'minion',
},
},
})
if (!res.ok) throw new Error(`GitHub returned ${res.status}: ${await res.text()}`)
const user = await res.json()
return { login: user.login }
} A login in the result means the integration, its token and the allowed host all line up. You can also read the status with minion.integrations.get({ name: 'github' }).
Use it in a package
In package code, import createAuthenticatedFetch from minion:runtime. It returns a fetch function bound to the integration. Minion adds the Authorization header for you.
package.json:
{
"name": "@your-org/github-tools",
"exports": { "./whoami": "./src/whoami.ts" }
} src/whoami.ts:
import { createAuthenticatedFetch } from 'minion:runtime'
const github = createAuthenticatedFetch('github')
export default async function main() {
const res = await github('https://api.github.com/user', {
headers: { Accept: 'application/vnd.github+json', 'User-Agent': 'minion' },
})
if (!res.ok) throw new Error(`GitHub returned ${res.status}`)
const user = await res.json()
return { login: user.login }
} Save and publish it with minion.packages.save and publish: true. Publishing needs an owner or admin and a README.md that says the package needs the github integration. Other code can only import a published version. Then call it from execute:
import whoami from 'minion:@your-org/github-tools/whoami'
export default async function main() {
return whoami()
} Replace your-org with your organization slug. See /docs/packages for saving and publishing.
Use a personal access token instead
A fine-grained personal access token is a good fit when one automation needs read-only access to a few private repositories. OAuth has no read-only scope for private repositories. A fine-grained token does.
- Open github.com/settings/personal-access-tokens/new .
- Name the token and set an Expiration.
- Choose Only select repositories and pick them.
- Grant the permissions you need. Contents: Read-only and Pull requests: Read-only cover most reporting. Add Checks: Read-only and Commit statuses: Read-only to read CI results.
- Generate the token and copy it.
- In Minion, open app.minion.codes/app/secrets . Set Name to
githubToken, paste the token into Value, set Approved hosts toapi.github.com, and click Save secret.
Check it with execute:
export default async function main() {
const res = await fetch('https://api.github.com/user', {
headers: {
Accept: 'application/vnd.github+json',
Authorization: 'Bearer {{secret:githubToken}}',
'User-Agent': 'minion',
},
})
if (!res.ok) throw new Error(`GitHub returned ${res.status}`)
return { login: (await res.json()).login }
} Never paste the token into chat. See /docs/secrets .
Troubleshooting
- GitHub says the redirect_uri is not associated with this application. The Authorization callback URL on the GitHub app must be exactly
https://app.minion.codes/oauth/callback. No trailing slash. - 404 Not Found or empty results for a private repository. The token doesn't have the
reposcope. Add it to the app's Default scopes, or type it in Extra scopes and click Connect again. You approve the wider grant on GitHub. - Organization repositories are missing. The GitHub organization restricts OAuth App access. Ask an owner of that organization to approve your app in its third-party access settings.
- An error saying integration "github" may not send its token to a host. You called a host outside the app's API hosts. The preset allows
api.github.comanduploads.github.com. To add a host, save the app again with the full list in API hosts. - 403 with X-RateLimit-Remaining: 0. You hit the hourly rate limit. Wait for the reset time in
X-RateLimit-Reset. - The integration turns error and says it needs a person to reconnect. You revoked the grant on GitHub, or GitHub revoked an unused token. Minion marks the integration
errorand fires anintegration.auth.failedevent with areconnectUrl. Click Connect on the Integrations page. A package can subscribe tointegration.auth.failedto alert you. - Secret "githubToken" isn't approved for api.github.com. Open the secret on the Secrets page and approve
api.github.com.
For how OAuth integrations work in general, see /docs/oauth . To run code, see /docs/execute .