Repository navigation
Releases: jferrl/go-githubauth
Release list
v1.9.1
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.1Verify a download against checksums.txt:
sha256sum -c checksums.txt --ignore-missingThe library is unaffected by these artifacts:
go get github.com/jferrl/go-githubauth@v1.9.1v1.9.0
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.0Verify a download against checksums.txt:
sha256sum -c checksums.txt --ignore-missingThe library is unaffected by these artifacts:
go get github.com/jferrl/go-githubauth@v1.9.0v1.8.0
[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 witherrors.As; it unwraps toErrRateLimited, so
errors.Isand 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 attachesX-RateLimit-*to essentially every authenticated
response, so a terminalResource not accessible by integrationwas slept on for up
to 60s, retried, and returned wrapped inErrRateLimited. A 403 now counts as
throttled only when it carriesRetry-After, reports an exhausted budget, or says so
in its message. Callers branching onerrors.Is(err, ErrRateLimited)will no longer
match a permission failure (#63) WithApplicationTokenExpirationrejects values at or below 90 seconds, the 60s
clock-drift backdate plusDefaultExpirySkew, 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 documented1 * time.Minute, which is affected (#63)WithHTTPClientreuses 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 calledMiddleware(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 newErrMissingSecret, so a misconfigured deployment fails closed
(#61)
Fixed
- Named identifier types are accepted. The
Identifierconstraint is~int64 | ~string,
but the implementation type-switched on the exact dynamic type, sotype AppID int64
was rejected withunsupported 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 hungToken()
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) ErrRateLimitedandWithRetryOnThrottlegodoc 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 aghs_-prefixed JWT of about 520 characters
(announcement).
This library copies the token string intooauth2.Token.AccessTokenand never parses,
measures or validates it, and expiry is read fromexpires_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 ActionsGITHUB_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.comover 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 withurl.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/oauth2from 0.36.0 to 0.37.0 (#59) - Bumped
github/codeql-actionfrom 4 to 4.38.0 (#53, #55, #56, #57, #58, #60) - Bumped
actions/setup-gofrom 6 to 7 (#52)
Full Changelog: v1.7.0...v1.8.0
v1.7.0
[v1.7.0] - 2026-06-30
GitHub Enterprise Cloud (GHEC) support and a more foolproof installation-token configuration.
Added
- Custom Base URL: New
WithBaseURLoption sets the API base URL verbatim (only normalizing a trailing slash), mirroring howgo-githubtargets a custom endpoint. UnlikeWithEnterpriseURL, it does not append/api/v3/, enabling GitHub Enterprise Cloud with data residency (https://api.SUBDOMAIN.ghe.com/) and pointing the client at anhttptestserver in tests (#50)
Changed
- Order-independent options:
WithBaseURL,WithEnterpriseURL,WithHTTPClient, andWithRetryOnThrottlecan now be combined in any order. PreviouslyWithHTTPClientrebuilt the client and silently discarded a base URL or retry setting applied before it - Fail-loud configuration: An invalid base URL (or a
nilHTTP client) is now reported by the first call toToken()instead of silently falling back to the public GitHub API
Fixed
- HTTP client no longer mutated:
WithHTTPClientoperates 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
niltoWithHTTPClientnow yields a clear error instead of panicking
Maintenance
- Removed the deprecated, no-op
net.Dialer.DualStackfield from the pooled HTTP client - Renamed the unexported
githubClient.clientfield tohttpClientfor clarity
Tests
- Added coverage for
WithBaseURL(GHEC andhttptestURLs), option order-independence, fail-loud misconfiguration, and verification that the caller's HTTP client is not mutated
Dependencies
- Bumped
actions/cachefrom 5 to 6 (#49) - Bumped
actions/checkoutfrom 6 to 7 (#48) - Bumped
codecov/codecov-actionfrom 6 to 7 (#46)
Full Changelog: v1.6.0...v1.7.0
v1.6.0
✨ 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 forerrors.Is/errors.As.Middleware(secret, opts...)net/httpmiddleware with body restoration, 25 MiB default cap, and 401/413 short-circuits.- Functional options
WithMaxPayloadSizeandWithErrorHandler. - Suitable for direct use in queue, Lambda, or Cloud Run consumers.
http.Handle("/webhook", webhook.Middleware(secret)(handler))📦 Dependencies
- Bump
golang.org/x/oauth2from 0.34.0 → 0.36.0 - Bump
codecov/codecov-action5 → 6 - Bump
styfle/cancel-workflow-action0.13.0 → 0.13.1
⚠️ Breaking / Behavior Changes
- Minimum Go version is now 1.25 (transitively required by
golang.org/x/oauth2v0.36.0). README previously claimed 1.21; the actual floor is now enforced. - Token sources refresh 30s before expiry by default. Set skew to
0viaWithExpirySkew(0)/WithInstallationExpirySkew(0)to restore prior behavior.
Full Changelog: v1.5.1...v1.6.0
v1.5.1
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
- @luna-veil-8080 made their first contribution in #41
Full Changelog: v1.5.0...v1.5.1
v1.5.0
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
v1.4.1
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
What's Added
- Personal Access Token Support: New
NewPersonalAccessTokenSourcefunction 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
cleanHTTPClientimplementation 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