Chapter 27Lesson 01~190 minutes

GitHub Apps, OAuth Apps, Webhooks, Checks API, and Event-Driven Integrations: Concepts, Architecture, and Mental Model

Build the mental model for GitHub App identity, OAuth/user alternatives, short-lived installation tokens, verified webhook delivery, durable idempotence, and rich Checks feedback.

GitHub AppsOAuthWebhooksChecks APIIdempotence

Learning objectives

  • Distinguish GitHub App, OAuth App, PAT, and machine-user identity models.
  • Explain App registration, installation, private-key/JWT, installation-token, and permission boundaries.
  • Verify webhook HMAC and use delivery IDs for replay/idempotency control.
  • Explain out-of-order/redelivery behavior and current-state reconciliation.
  • Choose Checks versus commit-status feedback.

1. The problem: integrations are identities and services, not scripts with tokens

Chapter 26 treated the API as a versioned, permissioned contract. Chapter 27 adds a production concern: who is the automation, what event caused it to act, and how can the receiver prove that event really came from GitHub? A long-lived personal token copied into a daemon blurs those boundaries. A GitHub App gives automation its own identity, fine-grained permissions, installable repository scope, central webhooks, and short-lived installation access tokens.

The operating question is therefore not “how do I call the API?” It is “which identity model matches this service, what is the smallest installation/permission/event surface, how is an inbound delivery authenticated and deduplicated, and how does the service report a durable result?”

2. Mental model: event → verified delivery → scoped app identity → feedback

Concept / workflow diagram
              flowchart TD
                E["GitHub event"] --> W["GitHub App webhook"]
                W --> V["Verify HMAC on raw body"]
                V --> D["Deduplicate X-GitHub-Delivery"]
                D --> Q["Queue / state reconciliation"]
                Q --> I["Installation token"]
                I --> A["GitHub REST/GraphQL API"]
                A --> C["Check run or other scoped feedback"]
                C --> O["Logs + delivery/audit evidence"]
            

Every arrow is a trust boundary. GitHub emits an event to the App webhook. The receiver verifies X-Hub-Signature-256 against the exact raw request bytes before parsing. It uses X-GitHub-Delivery as the event/delivery identity so a redelivery cannot accidentally repeat a mutation. Only after the event is accepted does the integration obtain or reuse a short-lived installation token and call the API within the installation's repository selection and App permissions. A check run is one possible feedback channel; logs, delivery records, and API request IDs provide operational evidence.

3. GitHub App, OAuth App, PAT, and machine user are different identity models

Identity Acts as Access shape Credential posture Good fit
GitHub App installation The app installation/bot Fine-grained permissions + selected/all repositories Installation token expires after one hour; generated from App identity CI/security bots, integrations, services that must outlive a person
GitHub App user access token App acting on behalf of a user Intersection of app permission, installation access, and user access Can be configured to expire; current default expiration is eight hours when expiration is enabled User-driven product features that still need App governance
OAuth App token A user OAuth scopes plus the user's own access User token lifecycle; broader scope model Legacy/user-centric integrations; some enterprise-level resource cases
Fine-grained PAT A user Selected resource owner/repositories and permissions Longer-lived user credential chosen by owner Personal/admin automation when an App is disproportionate
Machine user A normal GitHub user account used by automation Whatever that user is granted Password/token/2FA/user lifecycle; may consume an enterprise seat Compatibility edge cases, not the default service-identity pattern

GitHub's current guidance generally prefers GitHub Apps over OAuth Apps for integrations because Apps can act independently of a user, use finer permissions, permit repository selection at installation time, and use short-lived installation tokens. Authentication and authorization remain separate: a valid installation token cannot access a repository outside that installation or an endpoint outside the App's permissions.

4. App registration, installation, JWT, and installation tokens

A GitHub App registration defines the App's metadata, callback/webhook configuration, requested permissions, and subscribed events. An installation attaches that App to a user or organization account and chooses the repositories it can access. The registration is the software identity; each installation is a tenant-specific authorization boundary.

To authenticate as the App itself, a server signs a JSON Web Token with the App private key. Current GitHub.com JWT rules require RS256, an iat value, an iss identifying the App, and an exp no more than ten minutes in the future. That JWT is not the normal repository-operation token. It is used to call App-level endpoints such as creating an installation access token. The resulting installation token expires after one hour and can be narrowed to repositories/permissions below the installation's maximum.

Credential boundary: The App private key is a high-value long-lived signing credential. Never commit, paste into tickets, print, or place it in a browser/client bundle. Rotate/revoke it like any other signing key. The mandatory labs in this chapter do not create a real private key.

5. Webhook deliveries: authenticity, identity, and lifecycle

A webhook is an outbound HTTP delivery from GitHub to an endpoint after a subscribed event. Important headers include X-GitHub-Event (event type), X-GitHub-Delivery (globally unique delivery/event GUID), and—when a secret is configured—X-Hub-Signature-256. GitHub computes the latter as HMAC-SHA256 over the request body with the webhook secret.

Verification must use the raw bytes as received and a constant-time comparison. Parsing JSON first and reserializing it can change whitespace/encoding and invalidate a correct signature. A valid signature proves possession of the configured shared secret; it does not mean the event is relevant. After verification, also validate event type, action, installation/repository identity, and any business preconditions.

GitHub currently expects a 2XX response within ten seconds on GitHub.com. Production receivers should perform cheap authentication/deduplication, enqueue durable work, and acknowledge quickly. GitHub does not automatically redeliver failed deliveries; recent deliveries can be manually/API-redelivered for three days. A requested redelivery keeps the same X-GitHub-Delivery, which makes delivery-ID deduplication an important correctness control.

6. Idempotence, replay defense, ordering, and current-state reconciliation

Webhook delivery is at-least-once in an operational sense because operators can redeliver the same event, and your network/proxy can cause duplicate application processing. Store the delivery GUID before performing irreversible work. A uniqueness constraint is stronger than an in-memory set because it survives process restarts and multiple workers.

Do not infer event order from arrival order. GitHub documents that deliveries can arrive out of order and may be delayed. If correctness depends on current repository state, use the payload to identify the resource, then perform a permissioned read of the authoritative API state before the mutation. Event timestamps help reconstruct sequence, but “latest event received” is not necessarily “latest state on GitHub.”

7. Checks API versus commit statuses

A check suite groups checks for a commit. A check run is an individual analyzer/test result with lifecycle state, conclusion, output, annotations, and optional requested actions. The older commit-status API is a simpler context + state model. Checks are preferable when a GitHub App must attach rich diagnostics to exact source lines or expose re-run/requested-action UX.

Current write boundary: GitHub's Checks guidance says write access for creating/updating check runs/suites is a GitHub App capability; OAuth Apps and ordinary authenticated users can read checks but cannot use the write API as that identity model. The mandatory chapter path therefore inspects a realistic check-run fixture. A live check publication is optional and requires a disposable GitHub App with Checks: write.

8. Read-only inspection before creating an integration

Before registering an App or webhook, identify the repository and current commit that the integration would observe. This proves scope without creating credentials:

gh auth status
gh repo view OWNER/atlas-c27-integration-lab --json nameWithOwner,visibility,defaultBranchRef
gh api -H "X-GitHub-Api-Version: 2026-03-10" \
  repos/OWNER/atlas-c27-integration-lab/commits/HEAD \
  --jq '{sha:.sha,author:.commit.author.name}'

gh api -H "X-GitHub-Api-Version: 2026-03-10" \
  repos/OWNER/atlas-c27-integration-lab/commits/HEAD/check-runs \
  --jq '{total_count,checks:[.check_runs[]|{name,status,conclusion,app:.app.slug}]}'

A zero check-run count is a valid hosted state. It does not imply that a check writer should immediately receive write permission.

9. DevOps connection: an integration is production control-plane software

When an integration can react to repository events and mutate checks/issues/deployments, it participates in the delivery control plane. A forged webhook, replayed delivery, stale installation token, over-broad App installation, or unbounded retry can produce organization-wide failure. Stable interfaces, least privilege, verified ingress, durable deduplication, bounded retry, and observable outcomes are therefore application requirements—not optional hardening.

Knowledge check

Why is a GitHub App installation token better suited than a developer PAT for an organization CI service?

What must be verified before parsing a webhook body?

A redelivered webhook has the same delivery GUID as the original. Should the derived mutation run again?

Why can a valid installation token still receive 403?

When are commit statuses a better fit than Checks API?

Summary

GitHub Apps give integrations a dedicated installable identity. The secure path is: verify event authenticity on raw bytes, classify event/action/scope, deduplicate by delivery GUID, reconcile current hosted state, obtain/reuse a short-lived installation token, perform the minimum authorized mutation, and publish observable feedback. OAuth/PAT/machine-user identities remain different tools with different lifecycle and authorization tradeoffs.

Next lesson

GitHub Apps, OAuth Apps, Webhooks, Checks API, and Event-Driven Integrations: Guided Hands-On Workflow and Core Operations

Official references

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.