All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Module path.
github.com/jferrl/go-githubauth(v1.x) is the supported module. The/v2path was published by accident and is permanently retracted: v2.0.0, v2.0.1 and v2.0.2 are all covered by theretractblock inv2/go.modat thev2.0.2tag, including v2.0.2 itself, sogo getresolves none of them andgo list -m -versionsreports no versions for that path. There will be no v2.That
v2.0.2tag is the only thing carrying the retraction — thev2/directory no longer exists onmain— so the tag must not be deleted or the retraction is lost.
-
The v1.9.0 release published its binaries and checksums but not the Homebrew cask. GoReleaser requires the tap token to be written as exactly
{{ .Env.VAR }}and rejects any other form; the config used{{ index .Env "VAR" }}. The rule is enforced when publishing, sogoreleaser checkand snapshot builds both accepted it.brew install jferrl/tap/githubauthworks from this release on. The v1.9.0 archives were unaffected and remain valid.
The library is unchanged. This release is the githubauth command line tool and the
machinery to distribute it, so a shell script or CI step can get an installation token
without a Go toolchain.
-
cmd/githubauth, a command line tool that prints an installation token or the App JWT, so a shell script or CI step can authenticate as a GitHub App without reimplementing the JWT-then-exchange chain. Install it withgo install github.com/jferrl/go-githubauth/cmd/githubauth@latest.The token is the only thing written to stdout, so
$(githubauth token)composes withcurland friends. Every flag falls back to an environment variable, and--keyaccepts a file path, the PEM itself, or-to read stdin so the key never has to touch disk.It adds no module dependencies. The CLI is built on the standard library's
flag, so the two-dependency footprint is unchanged for anyone importing the library. -
Prebuilt
githubauthbinaries on each release, for Linux, macOS and Windows on amd64 and arm64, with achecksums.txtto verify them. A tagged release builds them with GoReleaser; the library is unaffected and is still consumed withgo get. -
A Homebrew cask, so the CLI installs without a Go toolchain:
brew install jferrl/tap/githubauth
The cask is generated into jferrl/homebrew-tap when a release is tagged.
githubauth versionreported a pseudo-version for a binary that was not installed withgo install. A release build now carries its tag, and a build from a checkout falls back to the stamped commit.
A correctness release. Two changes alter behaviour callers may depend on; both are listed under Changed and are worth reading before upgrading.
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, soerrors.Isand the rendered error string are unchanged (#65)
- 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 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)
- 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.Verifynow returns the newErrMissingSecret, so a misconfigured deployment fails closed (#61)
- Named identifier types are accepted. The
Identifierconstraint is~int64 | ~string, but the implementation type-switched on the exact dynamic type, sotype AppID int64was 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 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)
ErrRateLimitedandWithRetryOnThrottlegodoc now describe the 403 contract they actually implement (#63)- Examples check the error from
resp.Body.Close(#54)
- Added godoc examples, package documentation,
llms.txt, and a comparison withghinstallation(#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 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
- 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)
- 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)
- 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: https://github.com/jferrl/go-githubauth/compare/v1.7.0...v1.8.0
GitHub Enterprise Cloud support and a more foolproof installation-token configuration.
- Custom base URL:
WithBaseURLsets the API base URL verbatim, normalizing only a trailing slash, mirroring howgo-githubtargets a custom endpoint. UnlikeWithEnterpriseURLit does not append/api/v3/, which enables GitHub Enterprise Cloud with data residency (https://api.SUBDOMAIN.ghe.com/) and pointing the client at anhttptestserver in tests (#50)
- Order-independent options:
WithBaseURL,WithEnterpriseURL,WithHTTPClientandWithRetryOnThrottlecan be combined in any order.WithHTTPClientpreviously 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 reported by
the first call to
Token()instead of silently falling back to the public GitHub API
WithHTTPClientoperates on a shallow copy, so the caller's*http.Client, which may be shared elsewhere, keeps its original transport- Passing nil to
WithHTTPClientyields a clear error instead of panicking
- Removed the deprecated, no-op
net.Dialer.DualStackfield from the pooled HTTP client - Renamed the unexported
githubClient.clientfield tohttpClient
- Coverage for
WithBaseURL(GHEC andhttptestURLs), option order-independence, fail-loud misconfiguration, and that the caller's HTTP client is not mutated
- Bumped
actions/cachefrom 5 to 6 (#49) - Bumped
actions/checkoutfrom 6 to 7 (#48) - Bumped
codecov/codecov-actionfrom 6 to 7 (#46)
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.6.0...v1.7.0
- External key store support:
NewApplicationTokenSourceFromSigneraccepts anycrypto.Signerwith an RSA public key, so the App private key never enters process memory. Works with AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault Transit, PKCS#11 HSMs and ssh-agent. Construction verifies the signer's public key is*rsa.PublicKey, since GitHub requires RS256 - Proactive token refresh:
ReuseTokenSourceWithSkewrefreshes a cached token whentime.Until(exp) <= skewrather than waiting for expiry to pass, closing the window where a request starts shortly before expiry and reaches GitHub already expired. Tune withWithExpirySkewandWithInstallationExpirySkew - Automatic retry on throttling: installation token fetches retry once on 429, or on
403 carrying
Retry-After/X-RateLimit-Reset. The sleep honors context cancellation and is capped at 60s, and a terminal throttle wrapsErrRateLimitedforerrors.Is. Opt out withWithRetryOnThrottle(false) webhooksubpackage: constant-time HMAC-SHA256 verification of GitHub deliveries.Verifywith sentinel errors (ErrMissingSignature,ErrInvalidSignatureFormat,ErrSignatureMismatch), andMiddlewarewith body restoration, a 25 MiB default cap and 401/413 short-circuits, configurable viaWithMaxPayloadSizeandWithErrorHandler
- Minimum Go version is 1.25, transitively required by
golang.org/x/oauth2v0.36.0. The README previously claimed 1.21 - Token sources refresh 30s before expiry by default. Pass
WithExpirySkew(0)orWithInstallationExpirySkew(0)to restore the previous behaviour
- Bumped
golang.org/x/oauth2from 0.34.0 to 0.36.0 - Bumped
codecov/codecov-actionfrom 5 to 6 - Bumped
styfle/cancel-workflow-actionfrom 0.13.0 to 0.13.1
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.5.1...v1.6.0
- Enterprise URL Handling: Fixed regression in GitHub Enterprise URL handling (#41)
- Tightened test conditions and added more tests for
WithEnterpriseURL
- Bumped
github.com/golang-jwt/jwt/v5from 5.3.0 to 5.3.1 (#39) - Bumped
golang.org/x/oauth2from 0.32.0 to 0.34.0 (#34, #36) - Bumped
actions/checkoutfrom 5 to 6 (#35) - Bumped
actions/cachefrom 4 to 5 (#37) - Bumped
golangci/golangci-lint-actionfrom 8 to 9 (#33) - Bumped
styfle/cancel-workflow-actionfrom 0.12.1 to 0.13.0 (#38)
Contributors: @luna-veil-8080
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.5.0...v1.5.1
This release removes the github.com/google/go-github/v74 dependency and implements a lightweight internal GitHub API client. While most users will experience no breaking changes, some API adjustments have been made:
-
Enterprise Configuration Simplified
- Before:
WithEnterpriseURLs(baseURL, uploadURL string)- required both base and upload URLs - After:
WithEnterpriseURL(baseURL string)- single base URL parameter - Migration: Remove the redundant upload URL parameter
- Before:
-
Type Changes (if you were using these types directly)
github.InstallationTokenOptions→githubauth.InstallationTokenOptionsgithub.InstallationPermissions→githubauth.InstallationPermissionsgithub.InstallationToken→githubauth.InstallationTokengithub.Repository→githubauth.Repository
- Internal GitHub API Client: New
github.gofile with minimal GitHub API implementation- Direct HTTP API calls to GitHub's REST API
InstallationTokenOptionstype for configuring installation token requestsInstallationPermissionstype with comprehensive permission structureInstallationTokenresponse type from GitHub APIRepositorytype for minimal repository representation
- Public Helper Function: Added
Ptr[T]()generic helper for creating pointers to any type (useful for InstallationTokenOptions)
- Removed Dependency: Eliminated
github.com/google/go-github/v74dependency - Removed Dependency: Eliminated
github.com/google/go-querystringindirect dependency - Simplified Enterprise Support: Streamlined from
WithEnterpriseURLs()toWithEnterpriseURL() - Updated Documentation: Package docs now reflect that the library is built only on
golang.org/x/oauth2 - Binary Size Reduction: Smaller binaries without unused go-github code
- Documentation: Fixed GitHub API documentation link for installation token generation
No action required - if you only use the public TokenSource functions, your code will continue to work without changes.
// Before (v1.4.x)
installationTokenSource := githubauth.NewInstallationTokenSource(
installationID,
appTokenSource,
githubauth.WithEnterpriseURLs("https://github.example.com", "https://github.example.com"),
)
// After (v1.5.0)
installationTokenSource := githubauth.NewInstallationTokenSource(
installationID,
appTokenSource,
githubauth.WithEnterpriseURL("https://github.example.com"),
)// Before (v1.4.x)
import "github.com/google/go-github/v74/github"
opts := &github.InstallationTokenOptions{
Repositories: []string{"repo1", "repo2"},
Permissions: &github.InstallationPermissions{
Contents: github.Ptr("read"),
},
}
// After (v1.5.0)
import "github.com/jferrl/go-githubauth"
opts := &githubauth.InstallationTokenOptions{
Repositories: []string{"repo1", "repo2"},
Permissions: &githubauth.InstallationPermissions{
Contents: githubauth.Ptr("read"), // Use the new Ptr() helper
},
}- ✅ Reduced Dependencies: 2 fewer dependencies (from 3 to 2 total)
- ✅ Smaller Binary Size: No unused go-github code included
- ✅ Better Control: Full ownership of GitHub API integration
- ✅ Easier Debugging: Simpler code path for troubleshooting
- ✅ Same Performance: All token caching and performance optimizations maintained
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.4.2...v1.5.0
- Replace external GitHub mock with local implementation
- Enhanced Token Reuse: Implemented
ReuseTokenSourceinNewApplicationTokenSourcefor improved token caching efficiency - Dependency Updates: Bumped
golang.org/x/oauth2from 0.30.0 to 0.31.0 - CI/CD Improvements: Updated GitHub Actions dependencies and workflow permissions
- Bumped
actions/setup-gofrom 5 to 6 - Bumped
actions/checkoutfrom 4 to 5
- Bumped
- Library Upgrade: Upgraded
github.com/google/go-githubto v74
- Security: Fixed code scanning alert regarding workflow permissions
- Bumped
golang.org/x/oauth2from 0.30.0 to 0.31.0 (#25) - Bumped
actions/setup-gofrom 5 to 6 (#26) - Bumped
actions/checkoutfrom 4 to 5 (#28) - Upgraded
github.com/google/go-githubto v74 (#29)
Contributors: @jferrl, @krancour (first contribution)
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.4.0...v1.4.1
- 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
- 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
- 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: https://github.com/jferrl/go-githubauth/compare/v1.3.0...v1.4.0
- Go Generics Support: Introduced generic constraint
Identifierinterface supporting bothint64App IDs andstringClient IDs in a singleNewApplicationTokenSourcefunction - Type-Safe Authentication: Automatic type inference eliminates the need for separate functions while maintaining type safety
- Enhanced Documentation: Official GitHub API references and JWT technical details while maintaining godoc compliance
- Unified
NewApplicationTokenSourcefunction now uses Go generics to support both int64 App IDs and string Client IDs - Go version requirement bumped to 1.21+ (required for generics support)
- Updated Go version to 1.25 in CI workflows and documentation
- Improved CI workflow configurations with updated GitHub Actions
- Eliminated code duplication between App ID and Client ID authentication flows
- Fixed go version usage from go.mod in GitHub Actions build (#12)
- Added Dependabot configuration to keep dependencies up to date (#13)
- Bumped
styfle/cancel-workflow-actionfrom 0.10.0 to 0.12.1 (#15) - Bumped
actions/checkoutfrom 4 to 5 (#18) - Bumped
codecov/codecov-actionfrom 4 to 5 (#19)
Contributors: @jferrl, @grinish21
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.2.1...v1.3.0
- Security: Fixed JWT vulnerability GO-2025-3553 by upgrading jwt dependency to v5.3.0 (#9)
Contributors: @grinish21
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.2.0...v1.2.1
- Bumped dependencies to latest versions (#8)
Contributors: @candiepih (first contribution)
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.1.1...v1.2.0
- Fixed 404 links in README documentation (#3)
- Bumped dependencies to latest versions (#6)
- Upgraded Go version to 1.23 (#7)
Contributors: @grinish21 (first contribution), @jferrl
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.1.0...v1.1.1
- GitHub Enterprise Server compatibility
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.0.2...v1.1.0
- Minor improvements and bug fixes
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.0.1...v1.0.2
- Minor improvements and bug fixes
Full Changelog: https://github.com/jferrl/go-githubauth/compare/v1.0.0...v1.0.1
- Initial Release: GitHub authentication utilities for Go applications
- JWT Generation: Generate JSON Web Tokens (JWT) for GitHub Apps using
NewApplicationTokenSource - Installation Tokens: Obtain GitHub App installation tokens using
NewInstallationTokenSource - Security Compliance:
- JWT expiration time limited to 10 minutes maximum
- Clock drift protection with 60-second buffer
- Configuration Options:
WithApplicationTokenExpiration: Customize JWT token expirationWithHTTPClient: Set custom HTTP clientWithInstallationTokenOptions: Configure installation token options
- OAuth2 Integration: Full compatibility with
golang.org/x/oauth2.TokenSourceinterface
- Comprehensive README with usage examples
- Integration examples with
go-githublibrary
Full Changelog: https://github.com/jferrl/go-githubauth/commits/v1.0.0
go-githubauth is a Go package that provides utilities for GitHub authentication, including generating and using GitHub App tokens, installation tokens, and personal access tokens. It implements the TokenSource interface from the golang.org/x/oauth2 package for seamless integration with existing OAuth2 workflows.
- Generate GitHub Application JWT tokens
- Obtain GitHub App installation tokens
- Personal Access Token support (classic and fine-grained)
- Advanced token caching with automatic refresh
- High-performance HTTP clients with connection pooling
- RS256-signed JWTs with proper clock drift protection
- Full OAuth2 compatibility
- GitHub Enterprise Server support
- Production-ready performance optimizations
For more information, see the README.