Serval’s GitHub integration connects your GitHub Organization, User account, or Enterprise to Serval so workflows can read repositories, manage teams, and call the GitHub API on your behalf. It authenticates exclusively through GitHub Apps - never personal access tokens. You choose between two Serval-managed apps with different access tiers, or bring a GitHub App owned by your own organization.Authentication: GitHub App installation only. Pick a Serval-managed app - Full Admin Access or Code Contributor Access - or choose Use Your Own GitHub App. The bring-your-own path offers two options: let Serval walk you through installing the app (Install with Serval), or connect an app your GitHub organization admin already installed out of band (App already installed) by pasting its credentials. Workflow API calls never rely on a stored long-lived token: a fresh, short-lived installation access token is minted for every call.Data sync: Workflow API calls run on demand. For Access Management, GitHub Teams are ingested on a fixed schedule every 16 hours, always as a full sync (GitHub does not support delta sync).
Retrieve detailed information about a GitHub repository. Runs without approval by default.
Get GitHub File Contents
Retrieve the contents of a file from a GitHub repository. Runs without approval by default.
List GitHub Repository Contents
List files and directories in a GitHub repository path. Runs without approval by default.
List GitHub Repositories
List all repositories in a GitHub organization. Runs without approval by default.
List GitHub Teams
List all teams in a GitHub organization - the only approved way to fetch teams. Runs without approval by default.
Add GitHub User to Team
Add a user to a GitHub team, with validation that the team exists. Requires the user’s GitHub username, not an email address. Requires installer approval by default.
List GitHub Enterprise Roles
List custom enterprise roles defined on your GitHub enterprise. Requires an enterprise-scoped install. Runs without approval by default.
Update GitHub Enterprise Administrator Role
Set an enterprise member’s administrator role to Owner or Billing Manager. Requires an enterprise-scoped install. Requires installer approval by default.
Generic REST API requests
Typed access to any endpoint in GitHub’s official REST API from custom workflows, limited by the installed app’s permissions.
Enterprise REST API requests
A dedicated action for enterprise-only GitHub endpoints, intended for enterprise-scoped installs.
GraphQL requests
Run queries and mutations against GitHub’s GraphQL API; GraphQL-layer errors are surfaced as failures rather than silently dropped.
Access Management for GitHub Teams
GitHub Teams are ingested as resources (full sync every 16 hours) with Member and Maintainer entitlements. Users can request team access through Serval, and membership is provisioned and deprovisioned automatically.
Anything defined in the GitHub API can be accessed through Serval.
What you need depends on which connect option you choose in the Connect GitHub modal.
Serval-managed app (Full Admin or Code Contributor)
Use Your Own GitHub App
Use Your Own GitHub App (already installed)
Nothing to create. Both Full Admin Access (“Read contents of selected repos, open pull requests, create and manage repos and teams, invite users”) and Code Contributor Access (“Read contents of selected repos, open pull requests, and comment on issues”) use GitHub Apps that Serval manages - no credentials are required.
The install must be performed by (or approved by) a GitHub Organization Owner. If you’re not an owner, your install lands in a pending state until an owner approves it in GitHub - see Gotchas below.
You’ll need a GitHub App owned by your organization, plus a client secret and a private key generated for it. Follow GitHub’s app settings pages in GitHub Developer Settings.
1
Open or create your GitHub App
Go to GitHub Developer Settings and create a new GitHub App, or open an existing one. For an org-owned app, use the org’s Settings → Developer settings → GitHub Apps.
2
Set the Callback URL
Copy the Callback URL shown in Serval’s connect form (it has a Copy button) and paste it into your app’s Callback URL field.
3
Enable OAuth during installation
Check “Request user authorization (OAuth) during installation”.
Serval needs this setting to mint installation tokens and complete the install handshake. Don’t skip it.
4
Generate a client secret
Under Client secrets, click Generate a new client secret and copy it.
GitHub only shows the client secret once. Copy it before leaving the page.
5
Generate a private key
Under Private keys, click Generate a private key and save the downloaded .pem file. You’ll paste its full contents into Serval, including the BEGIN/END lines.
6
Note the app's identifiers
From the app’s About section, note the numeric App ID, the Client ID (starts with “Iv”), and the Public link (your app’s public page on GitHub). These plus the client secret and .pem contents fill Serval’s form.
Use the key GitHub generates for you, unmodified. Serval’s validation only accepts the RSA private key format GitHub’s Generate a private key button produces (the file begins with -----BEGIN RSA PRIVATE KEY-----) - keys converted to other formats will be rejected.
Use this option when your security process requires the app to be installed separately by an authorized organization admin after the app and its permissions have been reviewed - not inline during Serval’s connect flow. Your admin creates the app, configures permissions, transfers it to the organization, and installs it entirely on GitHub; Serval never triggers the install and no OAuth callback is involved.Because Serval authenticates purely as the app (a signed JWT minted from the private key), this path needs no OAuth client secret and no “Request user authorization (OAuth) during installation” setting. You only collect three values, all readable by an org owner from the app’s settings and installed-apps pages:
1
Install the reviewed app on your organization
An organization owner installs the GitHub App on the org with the approved repository access, following your normal review/approval process.
2
Generate a private key
In the app’s Settings → Private keys, click Generate a private key and save the downloaded .pem file. Only an admin of the app can generate it, and GitHub shows it only at generation time.
3
Find the App ID and Installation ID
The numeric App ID is in the app’s About section. For the Installation ID, open the org’s Installed GitHub Apps settings and click Configure on the app - the number at the end of the URL (.../installations/<ID>) is the installation ID.
The private key is the sensitive credential on this path - it can mint installation tokens for the app, so treat it as a secret and prefer a dedicated key you can rotate or revoke independently. Possession of the key is also what authorizes the connection (there is no OAuth ownership check), which cleanly separates the admin’s install action on GitHub from the connect action in Serval.
Click Connect on GitHub in Serval. The modal asks you to “Choose the access level that best suits your needs” - pick Full Admin Access or Code Contributor Access.
2
Install the app on GitHub
Serval opens GitHub’s install screen. Pick the target organization (or user or enterprise account), then choose all repositories or only selected repositories, and click Install & Authorize.
3
Return to Serval
GitHub sends you back to Serval, which records the installation and names the connection after your org or user login (or the enterprise slug for Enterprise installs). No credentials are ever entered.
Repository selection and access tier are fixed at install time. Repositories can be adjusted later in GitHub’s installed-apps settings; switching tiers requires uninstalling in GitHub and reconnecting with the other tier.
Choosing Use Your Own GitHub App (“Connect with a GitHub App owned by your organization.”) switches the modal to a bring-your-own form with a toggle at the top: Install with Serval (the guided two-step form below) and App already installed (paste credentials for an app your admin installed out of band - see the next tab). Install with Serval is the default.
1
Step 1 - Set up your GitHub App
Copy the read-only Callback URL (the Copy button shows “Copied” for 2 seconds) into your GitHub App’s Callback URL setting, and make sure “Request user authorization (OAuth) during installation” is checked.
2
Step 2 - Enter your app's credentials
Display name (optional) - “A friendly name shown in Serval - you choose this.” Placeholder: “My Company GitHub App”.
GitHub App public link (required) - accepts the full Public link, a scheme-less form, or a bare slug; the form shows Detected slug: [slug] once parsed. If it can’t be parsed: Couldn't read the GitHub App slug from that link. Paste your app's Public link, e.g. https://github.com/apps/your-app-name. Backend errors: appSlug is required, appSlug must be a valid GitHub App slug.
App ID (required) - must be numeric. Errors: appId is required, appId must be numeric.
Client ID (required) - starts with “Iv”. Error: clientId is required.
Client secret (required, password field) - “The value you copied in step 4 (GitHub won’t show it again).” Error: clientSecret is required.
Private key PEM (required, multi-line) - paste the full .pem contents including the BEGIN/END lines. Serval validates the key by signing a test token. Errors: privateKey is required, privateKey must be a valid GitHub App private key: [error details].
3
Connect and install
Click Connect. Serval validates your entries, then sends you to GitHub to install your app - pick the account and repositories and click Install & Authorize. Serval then verifies that the installed app matches the App ID you entered; if they don’t match, the connection fails with Failed to create integration - double-check that the Public link and App ID belong to the same GitHub App.
Complete the GitHub install promptly - your submitted credentials are held for only 10 minutes. If the window lapses you’ll see Invalid or expired OAuth state and must resubmit the form.
Reconnecting: the form prefills Display name, GitHub App public link, App ID, and Client ID from the saved connection, but Client secret and Private key PEM always start blank and are required again - there is no keep-existing-secret option. Have the .pem file and a client secret on hand (or generate new ones in GitHub) before reconnecting.
In the Connect GitHub modal, choose Use Your Own GitHub App, then switch the toggle to App already installed. There is no callback URL to copy and no redirect to GitHub - the app is already installed, so you just enter its credentials and connect.
1
Enter your app's credentials
Display name (optional) - a friendly label shown in Serval; you choose it.
App ID (required) - must be numeric. Errors: appId is required, appId must be numeric.
Installation ID (required) - must be numeric. Errors: installationId is required, installationId must be numeric.
GitHub App public link (optional) - stored for reference; when provided it must parse to a valid slug (appSlug must be a valid GitHub App slug).
Private key PEM (required, multi-line) - paste the full .pem contents including the BEGIN/END lines. Errors: privateKey is required, privateKey must be a valid GitHub App private key: [error details].
2
Connect
Click Connect. Serval authenticates as the app to confirm the installation is real and belongs to the App ID you entered, records the connection, and names it after your organization or user login. If verification fails you’ll see Could not verify the GitHub App installation. Double-check the App ID, Installation ID, and private key, and confirm the app is installed on your organization.
Reconnecting: Display name, GitHub App public link, App ID, and Installation ID are prefilled from the saved connection, but the Private key PEM starts blank and is required again. The modal reopens on this option automatically when the saved connection was created this way.
This path is for organization or user installs. An enterprise-scoped app is rejected with this app is installed on a GitHub Enterprise. Use the GitHub Enterprise integration to connect an enterprise-scoped app - use the GitHub Enterprise integration instead.
Serval runs three health checks against a connected GitHub integration:
Test GitHub App Installation - verifies a token can be minted and works, by making a small test request (a sample of accessible repositories for org/user installs, or a single enterprise team for Enterprise installs).
Success: GitHub App installation for [name] is properly configured and functional - or, for enterprise installs, GitHub Enterprise App installation for [name] is properly configured and functional
Failure: GitHub App installation token for [name] is invalid or not working. followed by a status-specific hint:
401 - The GitHub App installation token is invalid or expired. Please reinstall the GitHub App.
403 - The GitHub App may not have the required permissions. Check the app's permission configuration.
404 - The GitHub App installation was not found. It may have been uninstalled or it may be awaiting approval from an admin of [name]. Visit https://github.com/organizations/[name]/settings/installations for more info.
500/502/503 - GitHub returned a server error. This is likely a temporary issue with GitHub's API - please try again later.
List GitHub Teams - confirms the integration can list teams in the connected scope (org teams, or enterprise teams for Enterprise installs).
Success: Successfully listed [number] teams in [name] - or, for enterprise installs, Successfully listed [number] enterprise teams in [name]
Failure: Unable to list GitHub teams in [name]. followed by the same 401/403/server-error hints; the generic 404 variant reads The requested resource was not found. This may indicate missing permissions or incorrect configuration.
List GitHub Repositories - confirms the integration can list accessible repositories for the org. Enterprise installs skip this check and report it as passing.
Success: Successfully listed [number] repositories for [name] - enterprise installs instead report Not applicable: this check only validates org/user installs. Enterprise install ([name]) covered by test-installation-token.
Failure: Unable to list GitHub repositories for [name]. followed by the same 401/403/404 (generic)/server-error hints.
If all three checks are green but a specific workflow still fails with a permission error, the cause is almost always install-time scoping: the access tier you chose (Full Admin vs Code Contributor), the repository selection (all vs selected), or - on Enterprise installs - workflows that require an organization install. Check the app’s settings in GitHub’s installed-apps page, and see the gotchas below.
If the person connecting isn’t a GitHub Organization Owner, GitHub treats the install as a request and Serval creates a pending connection. Until an owner approves the app in GitHub, every API call fails with GitHub installation is pending approval. Once approved, the connection completes automatically - Serval matches the pending record even if the approval finishes outside the original browser session, returning the approver to Serval (or showing GitHub installation completed. You can close this window. when no return destination was recorded). If more than one pending install exists for the same GitHub target, completion errors with multiple pending installations found for this GitHub target - please keep only one.
Connecting an app installed out of band (no inline install)
If your security process requires an authorized org admin to install the reviewed app separately rather than inline during a vendor’s connect flow, use Use Your Own GitHub App → App already installed. Serval authenticates as the app via a signed JWT, so this path needs no OAuth callback and no client secret - only the App ID, Installation ID, and private key. There is no 10-minute credential window and no pending-approval handshake: the admin installs the app on GitHub first, then anyone with the credentials connects it in Serval. Because there is no OAuth ownership check on this path, possession of the private key is the authorization - treat it as a secret and use a dedicated, rotatable key.
Custom-app installs have a 10-minute approval window
For Use Your Own GitHub App, submitted credentials are held for only 10 minutes. If your org requires admin approval, the connection rejects with GitHub App installation is pending approval. Ask a GitHub organization owner to approve the app, then reconnect it in Serval. - your credentials are deliberately kept so an immediate retry works, but only until the 10 minutes expire, after which you’ll see Invalid or expired OAuth state and must resubmit the form.
Reconnecting a custom app requires re-entering both secrets
On reconnect, Display name, GitHub App public link, App ID, and Client ID are prefilled, but Client secret and Private key PEM always start blank and are hard-required - submit is blocked and blanks are rejected with clientSecret is required / privateKey is required. There is no keep-existing-secret path. Have the .pem file and a client secret ready (or generate fresh ones in GitHub) before you start.
Enterprise installs have no org or repo permissions
An Enterprise-scoped install is tied to the enterprise, not an organization. Workflows that inherently target an organization fail with This workflow requires a GitHub organization install, but the connected install is enterprise-scoped ([name]). Team ingestion returns an empty set for enterprise installs, the repository health check is reported as not applicable, and enterprise-only endpoints require the dedicated enterprise API action.
Use GitHub usernames, not email addresses
Team ingestion never creates new Serval users, because GitHub emails may be missing or personal. The Add GitHub User to Team workflow rejects anything that looks like an email address with Invalid GitHub username: '[username]'. Please provide a GitHub username (not an email address). GitHub usernames typically contain only letters, numbers, and hyphens. Access Management provisioning is likewise instructed never to guess: its input is annotated “The target user’s GitHub username. Do not make guesses about the user’s username. Ask the user for their GitHub username.”
Uninstalling the app in GitHub breaks the connection immediately
Tokens are minted fresh for every API call, so an uninstall (or an unapproved install) surfaces right away as The GitHub App installation was not found. It may have been uninstalled or it may be awaiting approval from an admin of [name]. Visit https://github.com/organizations/[name]/settings/installations for more info.
Repository selection and access tier are fixed at install time
Which repositories Serval can read is decided on GitHub’s install screen (all vs selected) and managed afterward in GitHub’s installed-apps settings, not in Serval. The two Serval-managed tiers are separate GitHub Apps - switching tiers means uninstalling the current app in GitHub and reconnecting with the other one.
Teams sync is a full refresh every 16 hours
GitHub does not support incremental sync, so every scheduled run re-enumerates all teams, their repositories, and memberships. Newly created GitHub teams appear after the next scheduled sync or a manual resync.
Need help? Contact support@serval.com for assistance with your GitHub integration.