Skip to content

Releases: jferrl/go-githubauth

v1.9.1

Choose a tag to compare

@github-actions github-actions released this 19 Sep 11:47
50b8e00

Changelog

  • 5500ebe fix: publish the Homebrew cask

Installing the CLI

Download the archive for your platform above, or:

go install github.com/jferrl/go-githubauth/cmd/githubauth@v1.9.1

Verify a download against checksums.txt:

sha256sum -c checksums.txt --ignore-missing

The library is unaffected by these artifacts:

go get github.com/jferrl/go-githubauth@v1.9.1

v1.9.0

Choose a tag to compare

@github-actions github-actions released this 19 Sep 11:42
8761b3f

Changelog

  • 17a86ee feat: add a githubauth command line tool
  • 1240d11 feat: publish a Homebrew cask for the CLI
  • 0b56e29 feat: publish prebuilt CLI binaries with GoReleaser

Installing the CLI

Download the archive for your platform above, or:

go install github.com/jferrl/go-githubauth/cmd/githubauth@v1.9.0

Verify a download against checksums.txt:

sha256sum -c checksums.txt --ignore-missing

The library is unaffected by these artifacts:

go get github.com/jferrl/go-githubauth@v1.9.0

v1.8.0

Choose a tag to compare

@jferrl jferrl released this 18 Sep 10:02
e084df5

[v1.8.0] - 2026-09-18

A correctness release. Two changes alter behaviour callers may depend on; both
are listed under Changed and are worth reading before upgrading.

Added

  • RateLimitError{StatusCode, RetryAfter, Message}, the concrete error returned when
    GitHub throttles a request. It carries the wait the client computed from GitHub's own
    headers, so a caller running its own backoff no longer has to re-parse a response it
    never sees. Extract it with errors.As; it unwraps to ErrRateLimited, so
    errors.Is and the rendered error string are unchanged (#65)

Changed

  • A 403 is no longer treated as rate limiting just because it carries rate-limit
    headers.
    GitHub attaches X-RateLimit-* to essentially every authenticated
    response, so a terminal Resource not accessible by integration was slept on for up
    to 60s, retried, and returned wrapped in ErrRateLimited. A 403 now counts as
    throttled only when it carries Retry-After, reports an exhausted budget, or says so
    in its message. Callers branching on errors.Is(err, ErrRateLimited) will no longer
    match a permission failure (#63)
  • WithApplicationTokenExpiration rejects values at or below 90 seconds, the 60s
    clock-drift backdate plus DefaultExpirySkew, falling back to the 10 minute default.
    Below that bound the cache can never hold the token and every call re-signs. The
    README previously documented 1 * time.Minute, which is affected (#63)
  • WithHTTPClient reuses the application JWT across requests, matching the default
    transport, instead of re-signing on every installation-token request (#62)

Security

  • An empty webhook secret is refused instead of used as an HMAC key. HMAC accepts a
    zero-length key, so a deployment that called Middleware(nil) or read a missing
    secret from the environment verified every delivery against a key anyone can
    reproduce, and forged payloads reached the downstream handler as authentic. Verify
    now returns the new ErrMissingSecret, so a misconfigured deployment fails closed
    (#61)

Fixed

  • Named identifier types are accepted. The Identifier constraint is ~int64 | ~string,
    but the implementation type-switched on the exact dynamic type, so type AppID int64
    was rejected with unsupported identifier type (#63)
  • A short application token expiration no longer mints an already-dead JWT. Issuance is
    backdated 60s for clock drift and only the upper bound was clamped, so a 30 second
    expiration produced a token that had expired 30 seconds earlier (#63)
  • A non-positive installation ID fails as a configuration error before any network call,
    rather than as a 404 from GitHub (#62)
  • The wait for a response header is bounded. Dial, TLS handshake and idle connections
    were capped, but a server that accepted a connection and then stalled hung Token()
    indefinitely, holding the token cache mutex against every concurrent caller (#61)
  • The error body of a failed response is capped at 64 KiB (#63)
  • Three comments claimed a default application JWT is usable for 9m30s; the backdating
    makes it 8m30s (#63)
  • ErrRateLimited and WithRetryOnThrottle godoc now describe the 403 contract they
    actually implement (#63)
  • Examples check the error from resp.Body.Close (#54)

Documentation

  • Added godoc examples, package documentation, llms.txt, and a comparison with
    ghinstallation (#54)
  • README reduced from 587 to 148 lines (#54)
  • GitHub stateless installation tokens: no action required. GitHub is replacing the
    short opaque installation token with a ghs_-prefixed JWT of about 520 characters
    (announcement).
    This library copies the token string into oauth2.Token.AccessToken and never parses,
    measures or validates it, and expiry is read from expires_at, so both formats work
    unchanged. GitHub Enterprise Server is out of scope; Enterprise Cloud and Data
    Residency endpoints are in scope, as is the Actions GITHUB_TOKEN

Tests

  • Both installation token formats, stateless and classic opaque, are pinned for verbatim
    passthrough
  • Every reachable branch is covered, and a test that reached example.com over the
    network on each CI run was replaced with ones that exercise what their names claim
    (#66)

Internal

  • Dropped two branches no input can reach, and replaced a relative-reference endpoint
    resolution with url.URL.JoinPath, which cannot fail and preserves an Enterprise
    /api/v3/ prefix by construction (#66)

Dependencies

  • Moved to the Go 1.26 toolchain
  • Bumped golang.org/x/oauth2 from 0.36.0 to 0.37.0 (#59)
  • Bumped github/codeql-action from 4 to 4.38.0 (#53, #55, #56, #57, #58, #60)
  • Bumped actions/setup-go from 6 to 7 (#52)

Full Changelog: v1.7.0...v1.8.0

v1.7.0

Choose a tag to compare

@jferrl jferrl released this 30 Jun 14:54
3d8cba2

[v1.7.0] - 2026-06-30

GitHub Enterprise Cloud (GHEC) support and a more foolproof installation-token configuration.

Added

  • Custom Base URL: New WithBaseURL option sets the API base URL verbatim (only normalizing a trailing slash), mirroring how go-github targets a custom endpoint. Unlike WithEnterpriseURL, it does not append /api/v3/, enabling GitHub Enterprise Cloud with data residency (https://api.SUBDOMAIN.ghe.com/) and pointing the client at an httptest server in tests (#50)

Changed

  • Order-independent options: WithBaseURL, WithEnterpriseURL, WithHTTPClient, and WithRetryOnThrottle can now be combined in any order. Previously WithHTTPClient rebuilt the client and silently discarded a base URL or retry setting applied before it
  • Fail-loud configuration: An invalid base URL (or a nil HTTP client) is now reported by the first call to Token() instead of silently falling back to the public GitHub API

Fixed

  • HTTP client no longer mutated: WithHTTPClient operates on a shallow copy, so the caller's *http.Client (which may be shared elsewhere) keeps its original transport
  • No panic on nil client: passing nil to WithHTTPClient now yields a clear error instead of panicking

Maintenance

  • Removed the deprecated, no-op net.Dialer.DualStack field from the pooled HTTP client
  • Renamed the unexported githubClient.client field to httpClient for clarity

Tests

  • Added coverage for WithBaseURL (GHEC and httptest URLs), option order-independence, fail-loud misconfiguration, and verification that the caller's HTTP client is not mutated

Dependencies

  • Bumped actions/cache from 5 to 6 (#49)
  • Bumped actions/checkout from 6 to 7 (#48)
  • Bumped codecov/codecov-action from 6 to 7 (#46)

Full Changelog: v1.6.0...v1.7.0

v1.6.0

Choose a tag to compare

@jferrl jferrl released this 20 Apr 10:33

✨ Features

External key store support for GitHub App JWTs

Added NewApplicationTokenSourceFromSigner which accepts any crypto.Signer with an RSA public key. Enables signing via AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault Transit, PKCS#11 HSMs, or ssh-agent — the private key never touches process memory. Validates at construction that the signer's public key is *rsa.PublicKey (GitHub requires RS256).

signer, _ := kms.NewSigner(ctx, keyID) // any crypto.Signer backed by RSA
ts, err := githubauth.NewApplicationTokenSourceFromSigner(appID, signer)

Proactive token refresh with configurable skew

New ReuseTokenSourceWithSkew refreshes cached tokens when time.Until(exp) <= skew instead of waiting for expiry to pass. Closes the in-flight 401 window where a request starts shortly before expiry and reaches GitHub already expired.

NewApplicationTokenSource and NewInstallationTokenSource now wrap with DefaultExpirySkew (30s); tune via WithExpirySkew / WithInstallationExpirySkew. Zero/negative skew delegates to oauth2.ReuseTokenSource verbatim for backwards compatibility.

Automatic retry on installation token throttling

createInstallationToken now performs a single automatic retry when GitHub returns 429, or 403 with Retry-After / X-RateLimit-Reset headers. Sleep honors context cancellation and is capped at 60s. Terminal throttle errors wrap ErrRateLimited for errors.Is branching. Opt out via WithRetryOnThrottle(false).

New webhook subpackage

Added a webhook package for verifying GitHub webhook deliveries using constant-time HMAC-SHA256:

  • Verify(secret, body, signature) with sentinel errors (ErrMissingSignature, ErrInvalidSignatureFormat, ErrSignatureMismatch) wrapped for errors.Is / errors.As.
  • Middleware(secret, opts...) net/http middleware with body restoration, 25 MiB default cap, and 401/413 short-circuits.
  • Functional options WithMaxPayloadSize and WithErrorHandler.
  • Suitable for direct use in queue, Lambda, or Cloud Run consumers.
http.Handle("/webhook", webhook.Middleware(secret)(handler))

📦 Dependencies

  • Bump golang.org/x/oauth2 from 0.34.0 → 0.36.0
  • Bump codecov/codecov-action 5 → 6
  • Bump styfle/cancel-workflow-action 0.13.0 → 0.13.1

⚠️ Breaking / Behavior Changes

  • Minimum Go version is now 1.25 (transitively required by golang.org/x/oauth2 v0.36.0). README previously claimed 1.21; the actual floor is now enforced.
  • Token sources refresh 30s before expiry by default. Set skew to 0 via WithExpirySkew(0) / WithInstallationExpirySkew(0) to restore prior behavior.

Full Changelog: v1.5.1...v1.6.0

v1.5.1

Choose a tag to compare

@jferrl jferrl released this 09 Feb 09:56

What's Changed

  • chore(deps): bump golang.org/x/oauth2 from 0.32.0 to 0.33.0 by @dependabot[bot] in #34
  • chore(deps): bump golangci/golangci-lint-action from 8 to 9 by @dependabot[bot] in #33
  • chore(deps): bump actions/checkout from 5 to 6 by @dependabot[bot] in #35
  • chore(deps): bump golang.org/x/oauth2 from 0.33.0 to 0.34.0 by @dependabot[bot] in #36
  • chore(deps): bump actions/cache from 4 to 5 by @dependabot[bot] in #37
  • chore(deps): bump github.com/golang-jwt/jwt/v5 from 5.3.0 to 5.3.1 by @dependabot[bot] in #39
  • chore(deps): bump styfle/cancel-workflow-action from 0.12.1 to 0.13.0 by @dependabot[bot] in #38
  • Fix regression in github enterprise url handling #40 by @luna-veil-8080 in #41

New Contributors

Full Changelog: v1.5.0...v1.5.1

v1.5.0

Choose a tag to compare

@jferrl jferrl released this 28 Oct 11:29
c395bf5

What's Changed

  • chore(deps): bump github/codeql-action from 3 to 4 by @dependabot[bot] in #31
  • chore(deps): bump golang.org/x/oauth2 from 0.31.0 to 0.32.0 by @dependabot[bot] in #30
  • refactor!: remove go-github dependency and implement internal GitHub API client by @jferrl in #32

Full Changelog: v1.4.2...v1.5.0

v1.4.2

Choose a tag to compare

@jferrl jferrl released this 19 Sep 07:11

Full Changelog: v1.4.1...v1.4.2

v1.4.1

Choose a tag to compare

@jferrl jferrl released this 19 Sep 06:27

What's Changed

  • chore: Use ReuseTokenSource in NewApplicationTokenSource by @jferrl in #22
  • chore(deps): bump golang.org/x/oauth2 from 0.30.0 to 0.31.0 by @dependabot[bot] in #25
  • chore(deps): bump actions/setup-go from 5 to 6 by @dependabot[bot] in #26
  • Potential fix for code scanning alert no. 1: Workflow does not contain permissions by @jferrl in #27
  • chore(deps): bump actions/checkout from 4 to 5 by @dependabot[bot] in #28
  • chore: upgrade github.com/google/go-github to v74 by @krancour in #29

New Contributors

Full Changelog: v1.4.0...v1.4.1

v1.4.0

Choose a tag to compare

@jferrl jferrl released this 30 Aug 10:51
732f060

What's Added

@jferrl in #21

  • Personal Access Token Support: New NewPersonalAccessTokenSource function for classic and fine-grained personal access tokens
  • Advanced Token Caching: Implemented dual-layer token caching system using oauth2.ReuseTokenSource
    • JWT tokens cached until expiration (up to 10 minutes)
    • Installation tokens cached until expiration (up to 1 hour)
  • High-Performance HTTP Client: Custom cleanHTTPClient implementation with connection pooling
    • Based on HashiCorp's go-cleanhttp patterns for production reliability
    • HTTP/2 support with persistent connections
    • No shared global state to prevent race conditions

What's Changed

  • Significant Performance Improvements: Up to 99% reduction in unnecessary token generation and GitHub API calls
  • Enhanced Documentation: Added comprehensive examples for personal access token usage
  • Optimized Memory Usage: Reduced object allocation through intelligent token reuse

Performance

  • GitHub App JWTs: Cached and reused until expiration instead of regenerating on every API call
  • Installation Tokens: Cached until expiration, dramatically reducing GitHub API rate limit consumption
  • Connection Pooling: HTTP connections reused across requests for faster GitHub API interactions
  • Production Ready: Optimized for high-throughput applications and CI/CD systems

Full Changelog: v1.3.0...v1.4.0